当输入为 None 时,函数的名称类似于 Option.bind that returns Some(x)

Name for function like Option.bind that returns Some(x) when input is None

普通的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。如果订单通过约束,它们 return Some order,否则 None(因此可以使用 Option.bind 组合)。现在,如果约束是 None,它本质上是一个空操作,Some order 应该是 returned。我可以使用上面的函数分解出这部分逻辑,而不是让所有约束函数都接受 'Constraint option(然后需要在组合过程中应用)。

我最初将该函数称为 bindConstraint,但它完全是通用的,与我的用例无关(参考 Mark Seemann 的 article on the topic)。由于它与 bind 相似,我想知道是否有一个标准名称。

让我们看看您的函数类型签名:

// ('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 (如果选项是,则提供默认值None).

所以我可能会称它为 defaultMapmapDefault

嗯...

我想知道你是否排除了 'U,你最终在 reader monad 中工作,然后你的函数是 option.bind 无事可做!

'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 -> 布尔值

更简单一点?...然后您只需使用 "where"...(您可以在计算表达式中执行此操作吗?...我认为您可以在 LINQ 中执行)。

P.S.

实际上你的代码的语义是不同的...你希望 None 被解释为恒等映射....

所以实际上我认为在你的世界里我会直接对约束进行操作

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 搞错了)