我试图过滤特定类型的混合数据类型,比如说float(理想情况下这会是动态的)
这是我的例子:
let testobj = [8.0 , 1.0, "bla" ; 8.0 , 1.0, "bla"]
let testfun data = data |> List.filter (fun a ->
match a.GetType() with
| float -> a
| _ -> 0.0)
现在这应该返回[8.0,1.0,0.0; testobj的8.0,1.0,0.0]但是我得到的函数是bool类型的错误
答案 0 :(得分:11)
这不是你想做的事。
严重。
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"
将打印您期望的内容。请注意,我使用了正确的数组语法和非列表语法。
然而这对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.toList
之后点击Array.map
,则会获得一个列表(如果您需要)。