简短概述:区别在于->
管道传递到第一个参数,而|>
管道传递到最后一个参数。即:
x -> f(y, z) <=> f(x, y, z)
x |> f(y, z) <=> f(y, z, x)
很不幸,实际情况中存在一些微妙的细节和影响,使得这变得更加复杂和令人困惑。请您耐心听我解释其中的历史。
在出现任何管道操作符之前,大多数函数式编程员都将函数的“对象”作为最后一个参数设计。这是因为使用部分函数应用可以更轻松地进行函数组合,并且如果未应用的参数在末尾,则在柯里化语言中更容易进行部分函数应用。
在柯里化语言中,每个函数只接受一个参数。看起来接受两个参数的函数实际上只接受一个参数,然后返回另一个函数,该函数接受另一个参数并返回实际结果。因此,以下两种写法是等价的:
let add = (x, y) => x + y
let add = x => y => x + y
换句话说,第一种形式只是第二种形式的语法糖。
这也意味着我们可以很容易地部分应用函数,只需提供第一个参数,它将返回一个接受第二个参数并生成结果的函数:
let add3 = add(3)
let result = add3(4) /* result == 7 */
如果没有柯里化,我们就必须将其包装在一个函数中,这样会更加繁琐:
let add3 = y => add(3, y)
现在,大多数函数都操作一个“主”参数,我们可以称之为函数的“对象”。例如,List
函数通常只对特定列表进行操作,而不是同时操作多个列表(当然,这种情况也会发生)。因此,将主参数放在最后使您能够更轻松地组合函数。例如,使用几个设计良好的函数,定义一个将可选值列表转换为具有默认值的实际值列表的函数就像这样简单:
let values = default => List.map(Option.defaultValue(default)))
如果使用“对象”优先设计的函数,你需要写:
let values = (list, default) =>
List.map(list, value => Option.defaultValue(value, default)))
据我所知,有人在 F# 中尝试玩弄代码时发现了一种常见的管道模式,并认为要么为中间值想出命名绑定太麻烦,要么使用太多括号嵌套函数调用顺序不对。因此他发明了管道前向运算符|>
。有了它,可以将管道写成如下形式:
let result = list |> List.map(...) |> List.filter(...)
替代
let result = List.filter(..., List.map(..., list))
或者
let mappedList = List.map(..., list)
let result = List.filter(..., mapped)
->
或|.
),而是使用管道前进操作符(|>
)并使用占位符参数(也仅适用于Reason),如果您需要将其导向“对象”优先函数,例如list |> List.map(...) |> Belt.List.keep(_, ...)
。
1这也与类型推断的交互方式有一些微妙的差异,因为类型是从左到右推断的,但在我看来,这对任何一种风格都没有明显的好处。
2因为它需要语法转换。它不能像管道前向操作符那样只实现为一个普通的运算符。
3例如,list |> List.map(...) -> Belt.List.keep(...)
不像你期望的那样工作。
4这意味着无法使用几乎在管道前向操作符存在之前创建的所有库,因为当然是针对原始的管道前向操作符创建的。这有效地将生态系统分成两个部分。
t
作为类型推断的第一位,同时仍然可以使用标准的 |>
运算符。Base 巧妙地使用了这个模式(例如,请参阅List,其中将函数 map
标记为 ~f
)。 - Kevin Ji->
的论点是,它似乎会破坏我所拥有的任何版本的 refmt
。当遇到 ->
时,它会显示语法错误。 - MCH|>
管道操作符,但是显然re-script
已经弃用了该操作符。假设re-script
将是bucklescript/reasonml
的未来,那么任何想要使用bs/rescript
的人都需要习惯使用->
管道操作符。 - masoodahm|>
通常被称为“管道正向”。它是在更广泛的OCaml社区中使用的辅助功能,不仅限于ReasonML。它将左侧参数“注入”到右侧函数中作为最后一个参数:
0 |> f == f(0)
0 |> g(1) == g(1, 0)
0 |> h(1, 2) == h(1, 2, 0)
// and so on
->
被称为“管道优先”,它是一种新的语法糖,将左侧参数注入到右侧函数或数据构造函数的第一个参数位置中:
0 -> f == f(0)
0 -> g(1) == g(0, 1)
0 -> h(1, 2) == h(0, 1, 2)
0 -> Some == Some(0)
注意:->
仅适用于BuckleScript编译成JavaScript时,对于本地编译不可用,因此不具有可移植性。更多详情请参见:https://reasonml.github.io/docs/en/pipe-first