给定一个列表[Some 1; 一些2; Some 3]我想要一个输出Some [1; 2; 3]。给定一个列表[Some 1; 无]应该产生无
我是F#的初学者,到现在为止,我已经完成了这两个工作,并创建了一个列表选项。我如何制作一个选项列表以通过此功能获得结果?
let lift a b =
match a, b with
| Some av, Some bv -> Some[av;bv]
| _, _ -> None
lift (Some 2) None
Run Code Online (Sandbox Code Playgroud)
在功能世界中,您所描述的通常称为sequence. 这是围绕泛型类型的顺序交换的概念:
List<Option<int>>到Option<List<int>>这是一个通用的方法:
module Option =
let (>>=) r f = Option.bind f r
let rtn v = Some v
let traverseList f ls =
let folder head tail = f head >>= (fun h -> tail >>= (fun t -> h::t |> rtn))
List.foldBack folder ls (rtn List.empty)
let sequenceList ls = traverseList id ls
// val traverseList : ('a -> 'b option) -> 'a list -> 'b list option
// val sequenceList : 'a option list -> 'a list option
Run Code Online (Sandbox Code Playgroud)
这里sequenceList有一个类型签名,'a option list -> 'a list option其也可以表示为List<Option<'a>> -> Option<List<'a>>. 这正是您想要的。
但是,但是,但是......与其他答案相比,这个答案似乎更加复杂。重点是什么?
关键是这个解决方案是通用的,可以应用于任何一元(或应用)类型。例如与Optionis类似的泛型类型,Result解决方案几乎与以前相同:
module Result =
let (>>=) r f = Result.bind f r
let rtn v = Ok v
let traverseList f ls =
let folder head tail = f head >>= (fun h -> tail >>= (fun t -> h::t |> rtn))
List.foldBack folder ls (rtn List.empty)
let sequenceList ls = traverseList id ls
// val traverseList : ('a -> Result<'b,'c>) -> 'a list -> Result<'b list,'c>
// val sequenceList : Result<'a,'b> list -> Result<'a list,'b>
Run Code Online (Sandbox Code Playgroud)
看?除了第 2 行和第 3 行,其余的都是一样的。
这使您可以抽象概念并将其放在您的脑海中。将来在您编程时,这将发生很多次,您需要迭代泛型类型,而类型最终会根据您的需要而反转。
但是没有必要重新发明轮子。对如何创建知识的武装sequence(和traverse)你可以往你的工具包,将其拉出,每当需要任何单一产品或应用性类型,是Async,Result,Option,等。
如果您想深入挖掘,请访问此网站,其中用清晰的图形和示例解释了概念:https : //fsharpforfunandprofit.com/posts/elevated-world-4/
let lift l =
if List.contains None l then None
else Some (List.map Option.get l)
Run Code Online (Sandbox Code Playgroud)