给出一个列表[Some 1;一些2; Some 3]我想要一个输出Some [1; 2; 3]。给定一个列表[Some 1; None]应该产生None
我是F#的初学者,到现在为止,我已经完成了这两个操作,并创建了一个列表选项。我如何制作一个选项列表以通过此功能获得结果?
let lift a b =
match a, b with
| Some av, Some bv -> Some[av;bv]
| _, _ -> None
lift (Some 2) None
答案 0 :(得分:3)
let lift l =
if List.contains None l then None
else Some (List.map Option.get l)
答案 1 :(得分:3)
在功能世界中,您所描述的通常称为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
此处sequenceList
的类型签名为'a option list -> 'a list option
,也可以表示为List<Option<'a>> -> Option<List<'a>>
。正是您想要的。
但是,但是,但是...与其他答案相比,这个答案似乎更加复杂。有什么意义?
重点是该解决方案是通用的,可以应用于任何单子(或适用性)类型。例如,与Option
类似的通用类型为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>
看到了吗?除了第2行和第3行,其余都相同。
这使您可以抽象概念并将其放在脑海中。将来,当您进行编程时,这会发生很多次,您需要遍历泛型类型,而这些类型最终会根据您的需求而倒置。
但是没有必要重新发明轮子。掌握了如何创建sequence
(和traverse
)的知识后,您可以随时进入工具包,并在需要任何单数或应用类型时将其拉出,无论Async
,Result
,Option
等
如果您想深入了解,请访问此网站,其中用清晰的图形和示例解释了这些概念:https://fsharpforfunandprofit.com/posts/elevated-world-4/
答案 2 :(得分:-1)
也许还有一些惯用的方法-使用模式匹配,序列和identity function:
let lift options =
match options |> Seq.contains None with
| true ->
None
| false ->
options
|> Seq.choose id
|> Some