折叠选项列表
Folding list of options
给定一个列表 [Some 1; Some 2; Some 3]
我想要一个输出 Some 6
。给定一个列表 [Some 1; None]
应该产生 None
.
但我发现以干净的方式实现这一目标比我想象的要困难一些。
我能想到的最好的就是这个
let someNums = [Some 1; Some 2; Some 3]
someNums
|> List.reduce (fun st v ->
Option.bind (fun x ->
Option.map (fun y -> x + y) st) v )
let lift op a b =
match a, b with
| Some av, Some bv -> Some(op av bv)
| _, _ -> None
let plus = lift (+)
[Some 1; Some 2; Some 3]
|> List.reduce plus
// val it : int option = Some 6
[Some 1; None]
|> List.reduce plus
// val it : int option = None
折叠
[Some 1; None]
|> List.fold plus (Some 0)
// val it : int option = None
[Some 1; Some 2; Some 3]
|> List.fold plus (Some 0)
// val it : int option = Some 6
[Some 1; None; Some 2]
|> List.fold plus (Some 0)
// val it : int option = None
这是 sequence
Gustavo 谈到的一个天真的实现:
let rec sequence =
function
| [] -> Some []
| (Some o :: os) ->
sequence os
|> Option.map (fun os' -> o::os')
| _ -> None
(请注意,这不是尾递归的,根本没有优化,所以如果你需要它用于大型列表,你应该转换它)
哪个会像 Gustavo 告诉你的那样起作用:
> sequence [Some 1; Some 2; Some 2] |> Option.map List.sum;;
val it : int option = Some 5
> sequence [Some 1; None; Some 2] |> Option.map List.sum;;
val it : int option = None
您可以通过为选项值定义 map2
函数来完成此操作:
let optionMap2 f x y =
match x, y with
| (Some x', Some y') -> Some (f x' y')
| _ -> None
这将使您能够编写所需的函数:
let sumSome = List.fold (optionMap2 (+)) (Some 0)
示例:
> [Some 1; Some 2; Some 3] |> sumSome;;
val it : int option = Some 6
> [Some 1; None; Some 3] |> sumSome;;
val it : int option = None
目前,optionMap2
函数在 F# 核心库中不可用,但是 probably will be part of the Option
module in the future。
给定一个列表 [Some 1; Some 2; Some 3]
我想要一个输出 Some 6
。给定一个列表 [Some 1; None]
应该产生 None
.
但我发现以干净的方式实现这一目标比我想象的要困难一些。
我能想到的最好的就是这个
let someNums = [Some 1; Some 2; Some 3]
someNums
|> List.reduce (fun st v ->
Option.bind (fun x ->
Option.map (fun y -> x + y) st) v )
let lift op a b =
match a, b with
| Some av, Some bv -> Some(op av bv)
| _, _ -> None
let plus = lift (+)
[Some 1; Some 2; Some 3]
|> List.reduce plus
// val it : int option = Some 6
[Some 1; None]
|> List.reduce plus
// val it : int option = None
折叠
[Some 1; None]
|> List.fold plus (Some 0)
// val it : int option = None
[Some 1; Some 2; Some 3]
|> List.fold plus (Some 0)
// val it : int option = Some 6
[Some 1; None; Some 2]
|> List.fold plus (Some 0)
// val it : int option = None
这是 sequence
Gustavo 谈到的一个天真的实现:
let rec sequence =
function
| [] -> Some []
| (Some o :: os) ->
sequence os
|> Option.map (fun os' -> o::os')
| _ -> None
(请注意,这不是尾递归的,根本没有优化,所以如果你需要它用于大型列表,你应该转换它)
哪个会像 Gustavo 告诉你的那样起作用:
> sequence [Some 1; Some 2; Some 2] |> Option.map List.sum;;
val it : int option = Some 5
> sequence [Some 1; None; Some 2] |> Option.map List.sum;;
val it : int option = None
您可以通过为选项值定义 map2
函数来完成此操作:
let optionMap2 f x y =
match x, y with
| (Some x', Some y') -> Some (f x' y')
| _ -> None
这将使您能够编写所需的函数:
let sumSome = List.fold (optionMap2 (+)) (Some 0)
示例:
> [Some 1; Some 2; Some 3] |> sumSome;;
val it : int option = Some 6
> [Some 1; None; Some 3] |> sumSome;;
val it : int option = None
目前,optionMap2
函数在 F# 核心库中不可用,但是 probably will be part of the Option
module in the future。