f#如何过滤特定类型的混合数据类型

时间:2014-09-26 17:08:54

标签: f#

我试图过滤特定类型的混合数据类型,比如说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类型的错误

1 个答案:

答案 0 :(得分:11)

这不是你想做的事。

严重。

F#希望列表是同质的,而且列表不是同质的。 floatstring不会共享一个共同的基类,因此您无法从中获取列表。

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#来说真的很不稳定。了解我如何使用类型来装饰ad?在我以前的代码中,语言可以解决所有问题。如果我不装饰,我会遇到编译器错误,因为我们真的违背了类型系统。

如果是你,我会倾向于先做这样的事情:

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,则会获得一个列表(如果您需要)。