正常的Option.bind
函数定义如下:
// ('T -> 'U option) -> 'T option -> 'U option
let bind f x =
match x with
| None -> None
| Some x' -> f x'
我需要稍微不同的版本:
// ('T -> 'U -> 'U option) -> 'T option -> ('U -> 'U option)
let myBind f x =
match x with
| None -> Some
| Some x' -> f x'
此功能是否有标准名称?(如果不是,我很乐意接受简明扼要的建议。)
对于感兴趣的读者,我的用例是这样的:我有一个业务对象(比如Order
)我想应用约束(订单日期,客户等)。将约束应用于例如Order
有签名'Constraint -> Order -> Order option
。如果订单通过约束,则返回Some order
,否则返回None
(因此可以使用Option.bind
组成)。现在,如果约束是None
,那么它本质上是一个无操作,并且应该返回Some order
。我没有让所有约束函数都接受'Constraint option
,而是可以使用上面的函数将这部分逻辑分解出来(然后需要在合成期间应用)。
我最初称这个函数类似bindConstraint
,但它完全是通用的,与我的用例无关(参见Mark Seemann的article on the topic)。由于它与bind
的相似性,我想知道是否有一个标准名称。
答案 0 :(得分:5)
让我们看看您的功能类型签名:
// ('T -> 'U -> 'U option) -> 'T option -> ('U -> 'U option)
'U -> 'U option
类型实际上可以从该签名中分解出来。我们称之为'V
类型。然后类型签名变为:
// ('T -> 'V) -> 'T option -> 'V
与Option.map
非常相似,其签名为:
// ('T -> 'V) -> 'T option -> 'V option
所以基本上,你的函数等同于Option.map
后跟defaultArg
将'V option
转换为'V
(如果选项为{{,则提供默认值) 1}})。
所以我可能称之为None
或defaultMap
。
答案 1 :(得分:1)
嗯...
我想知道你是否因为你最终在读者monad中工作,然后你的功能是IS选项。那么就没事了!
' U - > .....(' T - >' U选项) - > ' T选项 - > ' U选项
即。这是对字符串的约束吗?
let longerThan : int -> string -> string option =
fun i s ->
if (String.length s > i) then
Some s
else
None
这是你使用myBind
let foo = myBind longerThan (Some 1)
但这是没有myBind的代码
let bar =
fun s ->
(Some 1) |> Option.bind (fun i -> longerThan i s)
我们刚刚考虑了&U,我们在代码中编写代码。
(我的代码看起来更复杂,因为我们写的时间比使用你的绑定更好,如果我们交换参数顺序,那么你的版本看起来比我的更复杂)
我的另一个观察是,如果你只是在做约束,那么就不是
了' U - >布尔
有点简单?...然后你只需使用"其中" ...(你能用计算表达式做到这一点吗?......我认为你可以在LINQ中这样做。)
P.S。
实际上你的代码的语义是不同的......你希望None被解释为身份地图....
答案 2 :(得分:1)
所以实际上我认为在你的世界中我会直接对约束进行操作
type Constraint<'a> = 'a -> 'a option
let applyConstraint : Constraint<'a> option -> 'a -> 'a option =
function
| None -> Some
| Some f -> f
然后简单地组成约束;
let compose : Constraint<'a> -> Constraint<'a> -> Constraint<'a> =
fun c1 c2 -> fun a -> Option.bind c2 (c1 a)
(虽然我的c1和c2可能有错误的方法)