3

I have the following code:

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

Along with f the g function may or may not return Option as well. Since f has it as generic and doesn't have any generic constraints I can end up having Some(Some(z)) as a result. If fact all I want is either None or Some(z). How can I avoid double wrapping (preferably without imposing constraints on g)?

4

5 回答 5

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

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

f'a optionreturn 这意味着它可以返回或Some zaSome (Some y)f可以返回具有任意数量嵌套Somes的结果取决于g.


如果我的这个问题是正确的,那就是关于折叠嵌套Somes 的函数。可以手动编写:

let collapseOptions x =
    match x with
    | Some (Some y) -> y
    | _ -> None

如果这个问题是关于折叠所有嵌套Some的函数的,我想看看它的签名:)

于 2013-09-28T03:39:15.807 回答
3

在这种情况下,您有两个选择。约束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
于 2013-09-28T20:54:10.283 回答
3

使用Option.bind

let f g x = if x < 0 then None else Option.bind g (Some x)
于 2013-09-28T03:38:56.303 回答
2

使用可能的单子:

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 }
于 2013-09-30T04:17:22.963 回答
2

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

if x < 0 then
    None
else match g x with
     |Some(t) -> Some(t)
     |None -> None
于 2013-09-28T03:07:27.527 回答