我有以下代码:
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}}施加约束?)
答案 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 z
或Some (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 }