100

我正在通过阅读 DrBoolean 的来学习 javascript FP 。

我四处寻找函数式编程库。我找到了 Ramda 和 Folktale。两者都声称是函数式编程库。

但它们是如此不同:

  • Ramda似乎包含处理列表的实用函数:map、reduce、filter 和纯函数:curry、compose。它不包含任何处理 monad、functor 的内容。

  • 但是, Folktale不包含任何用于列表或函数的实用程序。它似乎在javascript中实现了一些代数结构,例如monad:Maybe,Task ...

实际上我发现了更多的库,它们似乎都属于这两类。Underscore 和 lodash 就像 Ramda。幻想世界,无点幻想就像民间故事。

这些非常不同的库都可以称为函数库吗?如果可以,是什么让每个库都成为函数库?

4

1 回答 1

189

功能特点

函数式编程或函数库的定义没有明确的界限。Javascript 中内置了函数式语言的一些特性:

  • 一流的高阶函数
  • Lambdas/匿名函数,带闭包

其他人可以在 Javascript 中小心完成:

  • 不变性
  • 参考透明度

还有一些是 ES6 的一部分,现在部分或全部可用:

  • 紧凑,甚至简洁的功能
  • 通过尾调用优化实现高性能递归

还有很多其他的东西确实超出了 Javascript 的正常范围:

  • 模式匹配
  • 懒惰的评价
  • 同音性

然后,一个库可以选择它试图支持的功能类型,并且仍然可以合理地称为“功能性”。

幻想世界规格

Fantasy-land是从数学范畴论和抽象代数移植到函数式编程的许多标准类型的规范,这些类型包括MonoidFunctorMonad。这些类型相当抽象,并且扩展了可能更熟悉的概念。例如,函子是可以map用函数覆盖的容器,就像数组可以mapArray.prototype.map.

民间故事

Folktale是实现 Fantasy-land 规范的各个部分的类型集合和一小部分配套实用功能。这些类型是MaybeEitherTask(非常类似于在其他地方称为 Future 和 Promise 更合法的表亲)和Validation

Folktale 可能是 Fantasy-land 规范最著名的实现,并且备受推崇。但是没有确定的或默认的实现。Fantasy-land 只指定抽象类型,实现当然必须创建这样的具体类型。Folktale 声称自己是一个函数库是很明确的:它提供了函数式编程语言中常见的数据类型,这些数据类型使得以函数式方式编程变得更加容易。

此示例来自Folktale 文档注意:不在最新版本的文档中),显示了如何使用它:

// We load the library by "require"-ing it
var Maybe = require('data.maybe')

// Returns Maybe.Just(x) if some `x` passes the predicate test
// Otherwise returns Maybe.Nothing()
function find(predicate, xs) {
  return xs.reduce(function(result, x) {
    return result.orElse(function() {
      return predicate(x)?    Maybe.Just(x)
      :      /* otherwise */  Maybe.Nothing()
    })
  }, Maybe.Nothing())
}

var numbers = [1, 2, 3, 4, 5]

var anyGreaterThan2 = find(function(a) { return a > 2 }, numbers)
// => Maybe.Just(3)

var anyGreaterThan8 = find(function(a) { return a > 8 }, numbers)
// => Maybe.Nothing

拉姆达

Ramda(免责声明:我是作者之一)是一种非常不同类型的库。它不为您提供新类型。1 相反,它提供了更容易对现有类型进行操作的功能。它是围绕将较小的函数组合成较大的函数、处理不可变数据、避免副作用的概念构建的。

Ramda 尤其适用于列表,但也适用于对象,有时也适用于字符串。它还以与 Folktale 或其他 Fantasy-land 实现互操作的方式委派了许多调用。例如,Ramda 的map函数,其操作类似于 on Array.prototype,所以R.map(square, [1, 2, 3, 4]); //=> [1, 4, 9, 16]。但是因为 FolktaleMaybe实现了 Fantasy-landFunctor规范,它也指定了地图,所以你也可以使用 Ramda 的map

R.map(square, Maybe.Just(5)); //=> Maybe.Just(25);
R.map(square, Maybe.Nothing); //=> Maybe.Nothing

Ramda 声称自己是一个函数库,在于它使组合函数变得容易,永远不会改变你的数据,并且只呈现纯函数。Ramda 的典型用法是通过组合更小的函数来构建更复杂的函数,如一篇关于Ramda 哲学的文章中所见

// :: [Comment] -> [Number]  
var userRatingForComments = R.pipe(
    R.pluck('username')      // [Comment] -> [String]
    R.map(R.propOf(users)),  // [String] -> [User]
    R.pluck('rating'),       // [User] -> [Number]
);

其他图书馆

实际上我发现了更多的库,它们似乎都属于这两类。下划线,lodash 很像 Ramda。幻想世界,无点幻想就像民间故事。

这并不准确。首先,Fantasy-land 只是一个库可以决定为各种类型实现的规范。Folktale 是该规范的众多实现之一,可能是最全面的实现之一,当然也是最成熟的实现之一。 Pointfree-fantasyramda-fantasy是其他的,还有更多

Underscorelodash表面上与 Ramda 很相似,因为它们是手抓包库,提供了大量功能,但内聚性比 Folktale 低得多。甚至特定功能也经常与 Ramda 重叠。但在更深层次上,Ramda 与那些库有很大不同的关注点。Ramda最接近的表亲可能是FKitFnucWu.js等库。

Bilby属于自己的一个类别,既提供了许多工具,例如 Ramda 提供的工具,也提供了一些与 Fantasy-land 一致的类型。(Bilby的作者也是Fantasy-land的原作者。)

你的来电

所有这些库都有权被称为功能库,尽管它们在功能方法和功能承诺程度方面差异很大。

其中一些库实际上可以很好地协同工作。Ramda 应该与 Folktale 或其他 Fantasy-land 实现很好地配合使用。由于它们的关注点几乎没有重叠,它们实际上并不冲突,但 Ramda 所做的足以使互操作相对顺畅。对于您可以选择的其他一些组合,这可能不太正确,但是 ES6 更简单的函数语法也可能会减轻集成的一些痛苦。

库的选择,甚至要使用的库风格,将取决于您的项目和您的偏好。有很多不错的选择可供选择,而且数量正在增长,其中许多正在大大改善。现在是在 JS 中进行函数式编程的好时机。


1嗯,有一个副项目,ramda-fantasy做一些类似于 Folktale 所做的事情,但它不是核心库的一部分。

于 2015-10-14T16:00:58.390 回答