为什么民间故事和ramda如此不同?

Aar*_*hen 83 javascript functional-programming ramda.js

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

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

但它们是如此不同:

  • Ramda似乎包含用于处理列表的实用函数:map,reduce,filter和pure函数:curry,compose.它不包含任何处理monad,functor的东西.

  • 但是,Folktale不包含列表或功能的任何实用程序.它似乎在monad中实现了javascript中的一些代数结构:也许,任务......

实际上我找到了更多的图书馆,它们似乎都属于这两个类别.下划线,lodash非常喜欢Ramda.Fantasy-land,pointfree-fantasy就像民间故事.

这些非常不同的库是否都可以被称为功能性的,如果是这样,是什么使每个库成为功能库?

Sco*_*yet 164

功能特点

功能编程或功能库的定义没有明确的界限.功能语言的一些功能内置于Javascript中:

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

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

  • 不变性
  • 参考透明度

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

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

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

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

然后,一个库可以挑选和选择它试图支持的各种功能,并且仍然可以合理地称为"功能".

幻想土地规格

Fantasy-land是从数学类别理论和抽象代数移植到函数式编程的许多标准类型的规范,类型如Monoid,FunctorMonad.这些类型相当抽象,可能会延伸更熟悉的概念.例如,Functors是可以通过map功能进行操作的容器,阵列可以map使用的方式Array.prototype.map.

民间故事

Folktale是一系列类型,实现了Fantasy-land规范的各个部分以及一小部分伴随实用功能.这些类型包括Maybe,Either,Task(非常类似于其他地方称为Future,以及更为合法的表兄),以及验证

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
Run Code Online (Sandbox Code Playgroud)

Ramda

Ramda(免责声明:我是其中一位作者)是一个非常不同类型的库.它不会为您提供新类型.1 相反,它提供的功能使其更容易在现有类型上操作.它围绕将较小的函数组合成较大的函数,使用不可变数据,避免副作用的概念构建.

Ramda特别在列表上运行,但也在对象上运行,有时在字符串上运行.它还以这样一种方式委托它的许多调用,它将与Folktale或其他Fantasy-land实现互操作.例如,Ramda的map功能,操作类似于on Array.prototype,所以R.map(square, [1, 2, 3, 4]); //=> [1, 4, 9, 16].但是因为Folktale Maybe实现了Fantasy-land Functor规范,它也指定了地图,你也可以使用Ramda's map:

R.map(square, Maybe.Just(5)); //=> Maybe.Just(25);
R.map(square, Maybe.Nothing); //=> Maybe.Nothing
Run Code Online (Sandbox Code Playgroud)

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]
);
Run Code Online (Sandbox Code Playgroud)

其他图书馆

实际上我找到了更多的图书馆,它们似乎都属于这两个类别.下划线,lodash非常喜欢Ramda.Fantasy-land,pointfree-fantasy就像民间故事.

那不是很准确.首先,Fantasy-land只是图书馆可以决定为各种类型实施的规范.Folktale是该规范的众多实现之一,可能是最全面的,当然是最成熟的. Pointfree-fantasyramda-fantasy是其他人,还有更多.

强调lodash,表面上看好像Ramda因为它们抓斗袋库,提供的功能有很大数量比像民间故事的凝聚力要少得多.甚至特定的功能也经常与Ramda的重叠.但在更深层次上,Ramda对这些图书馆的关注度却截然不同.Ramda最亲近的表兄弟可能是像FKit,FnucWu.js这样的图书馆.

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

你的来电

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

其中一些库实际上可以很好地协同工作.Ramda应该与Folktale或其他Fantasy-land实施很好地配合.由于他们的担忧几乎没有重叠,他们确实没有冲突,但Ramda确实足以使互操作相对平稳.对于您可以选择的其他一些组合,这可能不太正确,但ES6更简单的函数语法也可能会带来一些集成的痛苦.

库的选择,甚至是要使用的库的样式,都取决于您的项目和您的偏好.有很多好的选择,而且数量正在增长,其中许多都在大大改善.这是在JS中进行函数式编程的好时机.


1好吧,有一个侧面项目,ramda-fantasy做类似于Folktale的做法,但它不是核心库的一部分.

  • 不,`yield`可以更容易地执行由`Lazy`或`lz.js`完成的各种惰性列表处理.但它对语言水平的懒惰没有帮助.JS中的`someFunc(a + b)`首先添加`a`和`b`的值,然后将该结果作为参数提供给someFunc.Haskell中的等价物不会那样做.如果调用的函数从不使用该值,则它永远不会执行添加.如果它最终使用它,它被认为是一个表达式,直到需要它的结果为止.如果你从不做任何会强制它的事情(比如IO),它将永远不会实际执行计算. (6认同)
  • 这个答案应该是DrBoolean的书中的章节.:) (6认同)