gpt4 book ai didi

generics - F# 泛型函数过滤可区分联合列表

转载 作者:行者123 更新时间:2023-12-02 22:08:35 27 4
gpt4 key购买 nike

F#新手问题。我有一份受歧视工会的名单,例如:

type Type1 = { name:string;  id: int;  }
type Type2 = { x: float; y: float;}
type Type3 = { x: float; naam:string}
type Union1 =
| T1 of Type1
| T2 of Type2
| T3 of Type3
let lst1 = [ T1 {name="nnn"; id=3}; T2 {x=1.1; y=1.3}; T1 {name="naam1"; id=39}; T3{x=0.0; naam="xx"}];

//To filter out items of Type1, i do:
let fltT1 (l:list<Union1>) :list<Type1> =
let rec loop (l:list<Union1>) (acc:list<Type1>) =
match l with
| h::t -> match h with
// this is now specific per type
| T1{name=n;id=i} -> loop t ({name=n;id=i}::acc)
| _ -> loop t acc
| [] -> acc
loop l [] |> List.rev

如何使这样的函数通用以在调用中指定所需的输出类型(Type1|Type2|Type3)?

最佳答案

我的方法可能只是使用List.chooseSeq.choose。它比 filter/map 有优势,因为您只需要执行一次模式匹配,并且它比 fold 简洁得多。

lst1 
|> List.choose
(function
|T1 res -> Some res
|_ > None)

choose 类似于映射和过滤器的组合,它为结果为 Some 的每个元素返回 f(x) ,并且忽略所有 None 的元素。在此示例中,返回类型是 Type1 列表

<小时/>

基于特定联合案例参数化函数是不可能的,这是因为特定联合案例本身不是类型,它们只是联合类型的构造函数。您的示例中的 T1 不是类型,但 Union1 是。这意味着,在某些时候,需要显式模式匹配来分解它。 (请注意,并非所有函数式语言都是如此,Scala 的联合案例是通过继承建模的,但 F# 采用了 Haskell、Ocaml 等语言所使用的方法。)

正如 Fyodor Soikin 提到的,如果您愿意,您可以编写静态成员或函数来检查每种情况,例如:

static member tryAssumeT1 = function 
|T1 t1 -> Some t1
| _ -> None

然后您可以使用以下语法:

lst1 |> List.choose (tryAssumeT1)

关于generics - F# 泛型函数过滤可区分联合列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34120591/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com