如何在F#中避免双重包装?

时间:2013-09-28 03:04:21

标签: f#

我有以下代码:

let f g x = if x < 0 then None else Some(g x)

f一起,g功能也可能会返回Option,也可能不会返回f。由于Some(Some(z))具有通用性,并且没有任何通用约束,因此我最终可能会None。如果我想要的只是Some(z)g。如何避免双重包装(最好不对{{1}}施加约束?)

5 个答案:

答案 0 :(得分:2)

使用Option.bind

let f g x = if x < 0 then None else Option.bind g (Some x)

答案 1 :(得分:2)

> let f g x = if x < 0 then None else Some(g x)

val f : g:(int -> 'a) -> x:int -> 'a option

f会返回'a option,这意味着它可以返回Some zSome (Some y)等等。f可以返回任意数量的嵌套{ {1}} 取决于 Some。的类型


如果我的问题是正确的,那就是崩溃嵌套g的功能。它可以手动编写:

Some

如果这个问题是关于折叠所有嵌套let collapseOptions x = match x with | Some (Some y) -> y | _ -> None 的函数,我希望看到它的签名:)

答案 2 :(得分:2)

在这种情况下,您有两种选择。约束g以使类型'a -> Option<'b>或处理单独折叠嵌套选项值。

第一个版本:

let f (g: int -> Option<'b>) (x: int) = 
    if x < 0 then None else g x

在这种情况下,只要您希望将int -> 'b类型的普通函数传递给f,就需要将其提升为int -> Option<int>类型的函数。这是一个例子:

// Simple function of type: int -> int
let plusOne = (+) 1
let y = f x (pluseOne >> Some)

第二种选择是保留原始定义:

let f (g: int -> 'b) (x: int) = if x < 0 then None else Some (g x)

并在需要时简单地折叠结果。这可以通过Option.bind id轻松实现,如:

// This function has type: int -> Option<int>
let posPlusOne n = if n < 0 then None else Some (n + 1)
let y = f x posPlusOne |> Option.bind id

答案 3 :(得分:1)

解决此问题的最简单方法是使用匹配

if x < 0 then
    None
else match g x with
     |Some(t) -> Some(t)
     |None -> None

答案 4 :(得分:1)

使用monad monad:

https://github.com/fsharp/fsharpx/blob/master/src/FSharpx.Core/ComputationExpressions/Monad.fs

let f g x =
    maybe {
        if x<0 then None
        else
            let! gx = g x
            return f gx }