为什么 folktale 和 ramda 如此不同?

why are folktale and ramda so different?

我正在通过阅读 DrBoolean 的 book 来学习 javascript 函数式编程。

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

但它们是如此不同:

其实我找的库比较多,好像都属于这两类。 Underscore 和 lodash 就像 Ramda。幻想世界,无点幻想就像民间故事。

能否将这些截然不同的库都称为功能性,如果可以,是什么让每个库都成为功能性库?

功能特点

函数式编程或函数式库的定义没有明确的界限。 Javascript:

内置了一些函数式语言的特性
  • 一阶-class、高阶函数
  • Lambdas/Anonymous 个函数,带闭包

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

  • 不变性
  • 引用透明度

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

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

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

  • 模式匹配
  • 惰性评价
  • 同像性

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

梦幻乐园规格

Fantasy-land is a specification for a number of the standard types ported from mathematical Category Theory and Abstract Algebra to functional programming, types such as Monoid, Functor, and Monad。这些类型相当抽象,并且可能扩展了更熟悉的概念。例如,仿函数是可以用函数 map 覆盖的容器,就像使用 Array.prototype.map.

可以 map 覆盖数组一样

民间故事

Folktale is a collection of types implementing various parts of the Fantasy-land specification and a small collection of companion utility functions. These types are things like Maybe, Either, Task (very similar to what is elsewhere called a Future, and a more lawful cousin to a Promise), and Validation

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

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

// 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 函数与 Array.prototype 上的函数类似,因此 R.map(square, [1, 2, 3, 4]); //=> [1, 4, 9, 16]。但是因为 Folktale 的 Maybe 实现了 Fantasy-land Functor 规范,它也指定了地图,你也可以使用 Ramda 的 map :

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

Ramda 宣称自己是一个函数式库的原因在于让编写函数变得容易,从不改变你的数据,并且只提供纯函数。 Ramda 的典型用法是通过组合较小的函数来构建更复杂的函数,如 philosphy of Ramda

上的一篇文章所示
// :: [Comment] -> [Number]  
var userRatingForComments = R.pipe(
    R.pluck('username')      // [Comment] -> [String]
    R.map(R.propOf(users)),  // [String] -> [User]
    R.pluck('rating'),       // [User] -> [Number]
);

其他图书馆

Actually I found more libraries, they all seem fall into the two categorys. underscore, lodash are very like Ramda. Fantasy-land, pointfree-fantasy are like folktale.

这不太准确。首先,Fantasy-land 只是图书馆可以决定为各种类型实施的规范。 Folktale 是该规范的众多实现之一,可能是最全面的实现之一,当然也是最成熟的实现之一。 Pointfree-fantasy and ramda-fantasy are others, and there are many more.

Underscore and lodash are superficially like Ramda in that they are grab-bag libraries, providing a great number of functions with much less cohesion than something like Folktale. And even the specific functionality often overlaps with Ramda's. But at a deeper level, Ramda has very different concerns from those libraries. Ramda's closest cousins are probably libraries like FKit, Fnuc, and Wu.js.

Bilby自成一类,既提供了一些工具,例如Ramda提供的工具,也提供了一些与Fantasy-land一致的类型。 (Bilby的作者也是Fantasy-land的原作者。)

你来电

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

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

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


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