Option.bind等函数的名称,当输入为None

时间:2017-09-19 09:32:37

标签: f# naming

正常的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的相似性,我想知道是否有一个标准名称。

3 个答案:

答案 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}})。

所以我可能称之为NonedefaultMap

答案 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可能有错误的方法)