F#中的选项列表中的选项列表

Mah*_*han 4 f#

给定一个列表[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)

AMi*_*res 9

在功能世界中,您所描述的通常称为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)你可以往你的工具包,将其拉出,每当需要任何单一产品或应用性类型,是AsyncResultOption,等。

如果您想深入挖掘,请访问此网站,其中用清晰的图形和示例解释了概念:https : //fsharpforfunandprofit.com/posts/elevated-world-4/


gil*_*CAD 5

let lift l = 
    if List.contains None l then None
    else Some (List.map Option.get l)
Run Code Online (Sandbox Code Playgroud)