解决javascript 0-我从五年的 JavaScript 函数式编程学校学到了什么?

2023-09-05 0 4,905 百度已收录

作者|维克多·纳科里亚科夫

译者| 吴明

编辑| 秦云

这不是一篇关于学习 FP(函数编程)原理或 JavaScript FP 库的文章。 关于这个主题的文章有很多,但本文将重点介绍在项目中切换到 JavaScriptS 函数编程的冒险及其后果。

在故事开始之前,我一直是一名拥有10多年经验的专业程序员。 首先是 C++,然后是 C#,然后是 Python。 我仍然可以编写各种代码,而且我对模式和原理的掌握让我非常自信,我不认为有必要学习新东西。 我感觉自己已经“掌握了90%的编程真谛”。

2016年5月,我们开始开发XOD项目()。 XOD是一款专为数字爱好者打造的可视化编程IDE。 为了保持随意性,我们必须提供网页版的IDE。 网页版? 一定是JavaScript! 适用于所有 JavaScript 开发的 IDE? 是的,但我们不能只用 jQuery,我们需要更好的东西。

当时,一种新的重量级后端开发技术出现了:一种名为 React 的技术以及与之相伴的 Flux/Redux 模式。 在他们的文档和各种相关文章中,总是伴随着函数式编程的概念。 于是我开始学习FP。

哇! 这就像发现了一个新的台湾。 其实我也听说过Haskell、OCaml、LISP,但一开始我以为这种程序员是纯粹为了编程而编程的边缘知识分子,而不是为了发布产品而编程。 现在,我开始怀疑自己的专业能力。

函数式和响应式编程原则根植于 XOD 的 DNA 中,但在开发开始之前并不突出。 虽然我“发明”的或者借用其他产品的很多东西都是基于FP的。 为此,我们将使用一些重量级的现代 FRP JavaScript 创建一个 FRP 编程环境。

解决javascript 0-我从五年的 JavaScript 函数式编程学校学到了什么?

FP为项目带来了坚实的基础和灵活性。 我不想回到“经典”编程模型,但在可预见的未来,我将继续基于函数式编程原理开发所有新项目。

打破障碍

NPM 上可以找到大量的 JavaScript 函数式编程库,其中最值得关注的是 Ramda()。 它有点像 Lodash 或 Underscore,但基于 FP。 Ramda 提供了数十种用于处理数据和组合函数的函数。

函数本身还不错,但是需要和一些FP对象配合使用。 另一个库 RamdaFantasy() 提供了此类 FP 对象。 此外,还有其他 FP 库,例如 Sanctuary、Fluture 和 Daggy。 不过,建议先从 Ramda 开始,让你的大脑进入状态。

这是您可能遇到的第一个障碍。 在查看FP库的文档时,你会发现很多令人费解的问题。 令人困惑的参数顺序、外来术语和不清楚的函数值都是可能导致您停止尝试并转而求助于传统编程的问题。

首先,当你刚开始学习 FP 时,请阅读与特定编程语言或库无关的文章。 您首先需要了解整体的基本概念和优点,并评估如何将现有代码转换为新的编程模型。

许多关于函数式编程的文章都是由书呆子物理学家写的,未经初步训练就阅读它们是危险的:态射会扰乱你的思维,最终你什么也学不到。

幸运的是,现在有很多好文章。 对我影响最大的是:

无意义的疯狂

当我开始学习 FP 时,我遇到的第一个不寻常的概念是策略编程,也称为无点编程或无意义编码。

解决javascript 0-我从五年的 JavaScript 函数式编程学校学到了什么?

基本思想是省略函数参数名称,或者更确切地说,省略参数:

export const snapNodeSizeToSlots = R.compose(
  nodeSizeInSlotsToPixels,
  pointToSize,
  nodePositionInPixelsToSlots,
  offsetPoint({ x: WIDTH * 0.75, y: HEIGHT * 1.1 }),
  sizeToPoint
);

这是一个完全由其他函数组成的典型函数定义。 它不声明输入参数,但调用时需要指定。 没有上下文,你就可以理解这个函数的作用——输入一个大小并形成一些像素坐标。 但如果想知道具体的细节解决javascript 0,就需要对这些组合函数有深入的了解,并且这些函数可能是由其他函数组成的,并利用这个推论。

只要不被滥用,这是一项非常强大的技术。 当我们开始疯狂地使用 FP 方法时,我们将一切都转化为毫无意义的流问题,然后像解谜一样解决它们:

// Instead of
const format = (actual, expected) => {
  const variants = expected.join(‘, ‘);
  return `Value ${actual} is not expected here. Possible variants are: ${variants}`;
}
// you write
const format = R.converge(
  R.unapply(R.join(‘ ‘)),
  [
    R.always(“Value”),
    R.nthArg(0),
    R.always(“is not expected here. Possible variants are:”),
    R.compose(R.join(‘, ‘), R.nthArg(1))
 ]
);

好吧,完成了,出去并在代码审查中与其他人分享这个谜团。

接下来,您将接触到 monad 和纯度的概念。 也就是说,从现在开始,函数不能有任何副作用。 他们不能引用这个,他们不能引用时间和随机,他们不能引用给定参数之外的任何东西,甚至不能引用全局字符串常量或 pi。 您获取参数、工厂函数和生成器函数,将它们沿着嵌套链从最里面的函数传递到内部,然后展开函数签名。 现在您知道哪个是 Reader 或 Statemonad 了。 你用零星的映射和链感染你的代码,一碗日本面条已经计划好了!

第二点是函数式编程不是关于lambdacalculus、monad、态射和组合子,而是关于如何定义许多大的可组合函数及其不影响全局状态变化的参数、输入和输出。

换句话说,如果无意义的流在特定情况下效果更好,请使用它。 否则,请勿使用它。 不要仅仅因为可以使用 monad,而应该在它们真正解决问题时使用它们。 顺便说一句,你知道 Array 和 Promise 似乎是 monad 吗? 即使您不知道,也不影响您使用它们。 您应该训练您的直觉,直到您知道何时使用 monad,何时不使用。 练习需要一些时间解决javascript 0,在真正理解新事物之前不要过度使用它们。

尽可能使用没有副作用的大型可组合函数是值得的,所以尝试一下。

解决javascript 0-我从五年的 JavaScript 函数式编程学校学到了什么?

抛出异常或返回 null

转用FP风格后,有一个问题让我感到很苦恼。 在传统 JS 中,至少有两种方法来发出错误信号:

使用 FP 时您始终可以执行此操作,并且还有附加的 Either 和 Maybemonad。 那么现在应该如何处理错误呢? API应该如何设计?

Maybe/Either 在某些方面可能是更“正确”的方法,但用户可能不熟悉。 他们更习惯使用null和异常,但总是在控制台看到“undefineddisnotafunction”之类的错误。

第三,不要害怕用 Maybe 和 Either 处理错误。

我们来看看高铁的编程模型()。 如果你在公共 API 中使用 Maybe ,又怕理解困难,那就提供带有后缀的包装器,比如 Unsafe、Nullable、Exc 等,方便在命令式 JS 中使用。

令人上瘾的清晰度

如果您正在开发一个使用函数式编程原理的项目,您很快就会看到后果。 例如,代码审查需要较少的认知负荷。 在查看函数时,您只需要考虑函数本身,而不必担心组件数组更改后的后果。 你不需要考虑是使用浅拷贝、深拷贝还是引用。 你需要考虑的并不需要超出函数本身的几十行代码。

后来,当你听到新式代码时,总是显得很可疑。 “嗯......为什么我要改变一个对象的数组?为什么我要把这个值保存在这个数组中?它会在某个时刻改变我的对象的状态吗?”

第四点就是一定要选择FP兼容的库和懂FP的朋友,前者尤为重要。 如果团队中存在争议,有的人努力使用FP,而另一些人则随意违反FP原则,最终FP会失败。

解决javascript 0-我从五年的 JavaScript 函数式编程学校学到了什么?

雇用 FPJS 开发人员很困难,因为它设定了很高的门槛。 而且,一旦您找到这样的人,他们可能是最了解您的产品的人。 在 XOD,我们都是 FP 专家,我很高兴你们能一起工作。

损失与收益

函数式编程与主流形式有很大不同,因此主流工具可能没有用。

Flow 和 Typescript 无法正常工作,因为它们难以表达柯里化和参数多态性。 例如,虽然Ramda具有绑定功能,但它通常会提供错误警报,并且当确实发生错误时,错误消息很模糊。

您可以寻找一些在运行时执行类型检查的库,我们找到了这个。 不幸的是,它的扩展性不是很好,但性能损失通常小于函数本身的运行成本。 所以只能通过显式的方法进行类型检查,比如单元测试。

例如,如果您在深度函数组合中犯了错误并混淆了输入和输出类型,那么当您听到堆栈消息时,您可能会哭泣。

Error: Can’t find prototype Patch of Node with Id “HJbQvOPL-” from Patch “@/main”
 at /home/nailxx/devel/xod/packages/xod-func-tools/dist/monads.js:88:9
 at /home/nailxx/devel/xod/node_modules/sanctuary-def/index.js:2491:23
 at /home/nailxx/devel/xod/node_modules/sanctuary-def/index.js:860:20
 ...

大多数堆栈信息对于查找问题根源来说是没有意义的。 幸运的是,一旦 FP 代码运行成功,你就能感觉到它坚如磐石,以后不会给你带来任何意外。 如果在 JS 中使用 FP,显然需要进行一系列彻底的单元测试。

代码覆盖率和断点也可能存在问题。 FP 代码更像 CSS,而不是 JS。 请看一下XOD的源代码。

在 CSS 上设置断点并增量调试不是更有意义吗? CSS 文件的覆盖范围是多少? 事实上,不会是100%。 当你从声明式切换到命令式时,这个工具仍然可以工作,但问题是你的代码现在对于开发工具来说是碎片化的,开发体验已经发生了巨大的变化。

第五点,刚接触FP的时候,你会感觉更不开心。 当我第一次从 Windows 切换到 Linux 时,我也有过同样的经历。 从成熟的 IDE 切换到 Vim 也是如此。 我希望你能理解这些见解。

我们能否将两全其美结合在一起? 你不需要函数式编程的疯狂,却能获得函数式编程的卓越体验? 我觉得还可以。 还有其他基于 JS 的语言从一开始就面向函数式编程:Elm、PureScript、OCaml (BuckleScript) 和 ReasonML。

原文链接

后端顶部

“Top of Front End”是InfoQ旗下的一个专注于大型后端技术的垂直社区。 紧跟时代时尚,分享一线技术。 欢迎关注。

后端顶部

InfoQ 大后端技术社区

活动推荐

GMTC全球大后端技术大会携手顶级共创合作伙伴:APICloud企业互联网生态平台,筹备半年。 为您梳理了大后端领域的最新动态,并邀请了来自Google、Twitter、Instagram等国内一线专家,后端专家来分享他们最前沿的后端技术和最佳实践, iOS 社区专家 Mattt 和 ApolloGraphQL 负责人等专家也出席了会议。 它充满了有用的信息,不容错过。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 javascript 解决javascript 0-我从五年的 JavaScript 函数式编程学校学到了什么? https://www.wkzy.net/game/195579.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务