Сложенный список опций
Учитывая список [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 )
Ответы
Ответ 1
Вы можете выполнить это, указав функцию 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 #, но вероятно, будет частью модуля Option
в будущее.
Ответ 2
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
Ответ 3
Вот наивная реализация sequence
Густаво говорила о:
let rec sequence =
function
| [] -> Some []
| (Some o :: os) ->
sequence os
|> Option.map (fun os' -> o::os')
| _ -> None
(обратите внимание, что это не рекурсивно и не оптимизировано, поэтому вы должны преобразовать его, если вам понадобится его для больших списков)
Что будет работать так же, как Густаво сказал вам:
> 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