在我使用 OCaml 编程的实践中,我最近发现以下管道运算符对于创建函数非常有用。
let (>|) f g x = g (f x)
val ( >| ) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c = <fun>
我用它来替换如下代码:
fun s -> int_of_string s |> Int.hash
- : string -> int = <fun>
用更简单的方法:
int_of_string >| Int.hash
- : string -> int = <fun>
关联性很好:
int_of_string >| float_of_int >| string_of_float
- : string -> string = <fun>
这是否是对核心语言的有价值的改进?如果是,如何提交此贡献?
这称为膏抹组合。在 Haskell 中,运算符是
.
,在 Elm 中是 >>
。这些在纯函数式语言中运行良好,但不幸的是,受到 OCaml 等允许多态性和副作用的语言的值限制的影响,因此不太可能被接受。
这个例子说明了问题:
let f x = x (* val f : 'a -> 'a *)
let g x = x (* val f : 'a -> 'a *)
let h = f >| g (* val h : '_weak3 -> 'weak3 *)
let a = h "foo"
let b = h 42 (* Error: This expression has type int but an expression was expected of type string *)
有关 OCaml 中的值限制和多态性限制的详细信息,请参阅OCaml 手册。但它的要点(据我理解)是,如果存在突变和多态混合的可能性,类型变量就不能完全泛化,将被weak类型变量取代,这可能在某些时候确定稍后一点,就像第一次使用时一样,但不能是多态的。不幸的是,出于组合函数的目的,这使其处理起来非常具有限制性和混乱性。
OCaml 确实稍微放宽了值限制,并且允许此类函数(如果它们是语法函数)。这意味着你可以做
let h s = (f >| g) s
但是你也不妨这样做
let h s = s |> f |> g
或
let h s = g @@ f s