这不是你想做的。
说真的。
F# 希望列表是同质的,而您的列表不是同质的。 float 和 string 不共享一个公共基类,因此您不会从中获取列表。
F# 想要你做的是为此使用一个有区别的联合。所以如果你有这种类型:
type Composite =
| Num of float
| Str of string
你可以这样定义你的列表:
let data = [ Num(8.0); Num(1.0); Str("bla"); Num(8.0); Num(1.0); Str("bla") ]
从那里您可以对类型进行模式匹配,您的函数如下所示:
let testfun d = d |> List.map (fun a ->
match a with
| Num x -> a
| _ -> Num(0.0) )
data|> testfun |> printfn "%A"
输出将是:
[Num 8.0; Num 1.0; Num 0.0; Num 8.0 ; Num 1.0 ; Num 0.0;]
如果您最终想要浮动而不是合成,请执行以下操作:
let testfun1 d = d |> List.map (fun a ->
match a with
| Num x -> x
| _ -> 0.0 )
它摆脱了复合类型。该代码中的所有内容(我的意思是所有内容)都是类型强且类型安全的。
从实际维护的角度来看,我会避开匹配中的 _ 情况,而是使用我所有的类型,理由是如果我扩展 Composite 以包含另一种类型,我会希望编译器对我大喊大叫并查看每个使用它的函数,而不是默默地假设 0.0 或 Num(0.0) 确实是我想要的。
例如,如果我向该类型添加整数,如果我想对复合列表的内容求和,这将完全错误。
鉴于您被困在/一心想要弱类型的数据集,那么您想要这样的东西:
let testfun2 d = d |> Array.map (fun (a:Object) ->
match a with
| :? float as x -> x
| _ -> 0.0
)
let data:Object[] = [|8.0; 1.0; "bla"; 8.0; 1.0; "bla"|]
data |> testfun2 |> printfn "%A"
它将打印您期望的内容。请注意,我使用的是正确的数组语法和 not 列表语法。
然而这对 F# 来说真的很不靠谱。看看我必须如何用类型装饰a 和d?在我之前的代码中,语言可以解决所有问题。如果我也不修饰,我会得到编译器错误,因为我们真的违背了类型系统的本质。
如果我是你,我会倾向于先做这样的事情:
let recast d = d |> Array.map (fun (a:Object) ->
match a with
| :? float as x -> Num x
| :? string as x -> Str x
| _ -> raise (ArgumentException("that was unexpected: " + a.GetType().Name))
)
把它变成一个复合数组,现在是强类型。如果你在Array.map 之后添加|> Array.toList,你会得到一个列表(如果你想要的话)。