热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Reasonml中的->和|>有什么区别?

如何解决《Reasonml中的->和|>有什么区别?》经验,为你挑选了2个好方法。

一段时间的密集搜索为我提供了一些示例,其中人们在一个代码中使用两种类型的运算符,但通常它们看起来就像两种做某件事的方式,甚至具有相同的名称



1> glennsl..:

tl; dr:定义上的区别是,->管道传输到第一个参数,而|>管道传输到最后一个参数。那是:

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)

巧妙的功能设计

现在事实证明,大多数函数都在“ main”参数上操作,我们可以将其称为函数的“对象”。List函数通常在特定列表上运行,例如,一次不会运行多个列表(当然,当然也会发生)。因此,将main参数放在最后可使您更轻松地编写函数。例如,使用几个经过精心设计的函数,定义一个将可选值列表转换为带有默认值的实际值列表的函数非常简单:

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)

但这仅在main参数为last时才有效,因为它依赖于通过currying进行部分函数的应用。

然后... BuckleScript

随后是Bob,他是第一位创建BuckleScript的人,目的是将OCaml代码编译为Javascript。原因使BuckleScript被采用,然后Bob继续为BuckleScript创建一个名为的标准库BeltBelt通过将主要争论放在首位,几乎忽略了我上面解释的一切。为什么?这还有待解释,但是据我所知,主要是因为它对Javascript开发人员1更为熟悉。

Bob确实认识到管道运算符的重要性,因此他创建了自己的管道优先运算符|.,该运算符仅适用于BuckleScript 2。然后,Reason开发人员认为这看起来有点丑陋且缺乏方向,因此他们提出了->运算符,该运算符可以转换|.并像它一样工作……除了它的优先级不同,因此不能与其他任何东西很好地配合。3

结论

管道优先运算符本身并不是一个坏主意。但是在BuckleScript中实现和执行它的方式引起了很多混乱。它具有意想不到的行为,会鼓励不良的功能设计,除非一概而论4,否则根据您要调用的函数类型在不同的管道运算符之间进行切换时会加重沉重的认知负担。

因此,我建议避免使用管道优先运算符(->|.),如果需要通过管道传递至“对象”优先的函数(例如|>),请使用带有占位符参数的管道转发()(原因也除外)list |> List.map(...) |> Belt.List.keep(_, ...)


1这种类型与类型推断的交互方式也有一些细微的差异,因为类型是从左到右进行推断的,但这对两种样式的IMO都不明显。

2因为它需要语法转换。与管道转发不同,它不能仅作为普通运算符实现。

3例如,list |> List.map(...) -> Belt.List.keep(...) 无法按预期工作

4这意味着无法使用几乎所有在管道优先运算符存在之前创建的库,因为这些库当然是在考虑原始管道前移运算符的情况下创建的。这有效地将生态系统一分为二。



2> Yawar..:

|>通常称为“管道转发”。它是一个辅助功能,已在更广泛的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


推荐阅读
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 本文详细解析了JavaScript中相称性推断的知识点,包括严厉相称和宽松相称的区别,以及范例转换的规则。针对不同类型的范例值,如差别范例值、统一类的原始范例值和统一类的复合范例值,都给出了具体的比较方法。对于宽松相称的情况,也解释了原始范例值和对象之间的比较规则。通过本文的学习,读者可以更好地理解JavaScript中相称性推断的概念和应用。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • 本文介绍了Composer依赖管理的重要性及使用方法。对于现代语言而言,包管理器是标配,而Composer作为PHP的包管理器,解决了PEAR的问题,并且使用简单,方便提交自己的包。文章还提到了使用Composer能够避免各种include的问题,避免命名空间冲突,并且能够方便地安装升级扩展包。 ... [详细]
  • 用Vue实现的Demo商品管理效果图及实现代码
    本文介绍了一个使用Vue实现的Demo商品管理的效果图及实现代码。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
author-avatar
手机用户2602938293
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有