为什么民间传说和ramda如此不同?


96

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

我到处搜索功能编程库。我找到了Ramda和Folktale。两者都声称是功能编程库。

但是它们是如此不同:

  • Ramda似乎包含用于处理list的实用程序函数:map,reduce,filter和pure函数:curry,compose。它不包含任何要处理monad,函子的东西。

  • 但是Folktale不包含任何用于列表或函数的实用程序。似乎在JavaScript中实现了像monad这样的代数结构:Maybe,Task ...

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

难道这很不相同的库都被称为功能,如果有,是什么让每一个功能库?


1
使用适合您的需求和风格并有据可查的文件
charlietfl 2015年

1
我发现“函数式编程”确实有三种通常的含义,尤其是在JS中。1.集像阵列使用高阶纯函数。,离[1,2,3].map(fnSquare).reduce(fnSum)2.很大程度上学术“外观毫安没有变种 ” Y-组合子式的结构。3.使用Function.prototype修改其他功能的行为,例如var isMissingID=fnContains.partial("id").negate();
dandavis

10
Ramda的作者在这里:Ramda是一个相当底层的实用程序库。它旨在使JS中的某些功能样式更简单,尤其是通过组合功能来工作。Ramda与FantasyLand规范(包括Folktale之类的实现)配合得很好。这些库的设计目的有所不同。它们是基于识别常见的抽象数据类型并允许对其进行一致访问而构建的:诸如Monoid,Functor和Monads之类的东西。Ramda将与他们合作,并有一个辅助项目来创建一些项目,但是正如您所说,这是一个非常不同的重点。
Scott Sauyet,2015年

1
@KeithNicholas:是的,这里有个
垃圾

2
看看圣太- github.com/plaid/sanctuary 这是基于ramda而且涵盖幻想土地类型。
arcseldon '16

Answers:


179

功能特点

定义函数式编程或函数库没有明确的界限。Java语言内置了功能语言的某些功能:

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

其他人也可以小心地用Javascript完成:

  • 不变性
  • 参照透明

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

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

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

  • 模式匹配
  • 懒惰评估
  • 谐音

这样,一个库就可以选择要支持的功能类型,并且仍然可以合理地称为“功能”。

幻想世界规范

Fantasyland是从数学类别理论和抽象代数移植到函数式编程的许多标准类型的规范,例如MonoidFunctorMonad。这些类型相当抽象,并且扩展了可能更熟悉的概念。例如,map函子是可以map使用函数进行平移的容器,即使用可以对数组进行平移的方式Array.prototype.map

民间故事

Folktale是实现Fantasy-land规范各个部分的类型的集合,以及一小部分伴随的实用程序功能。这些类型包括MaybeEitherTask(非常类似于其他地方称为Future,并且是Promise的更合法的表亲)和验证

民间故事也许是《幻想世界》规范最著名的实现,并且受到了广泛的尊重。但是没有确定的或默认的实现。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功能与上的功能类似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的典型用法是通过组成较小的函数来构建更复杂的功能,如有关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幻想ramda幻想的人,有更多的

下划线lodash,表面上看好像Ramda因为它们抓斗袋库,提供的功能有很大数量少得多的凝聚力不是像民间故事。甚至特定的功能通常也与Ramda的功能重叠。但是从更深层次上讲,Ramda与这些库的关注点截然不同。Ramda最接近的表亲可能是FKitFnucWu.js之类的库

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

你的来电

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

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

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


1好吧,有一个附属项目,即ramda-fantasy其功能与Folktale相似,但它不是核心库的一部分。


1
可以这样说,ES6具有通过Yield进行延迟评估的功能吗?developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
马塞尔·拉莫特

8
yield可以更容易地做到懒列表的排序处理由完成Lazylz.js。但这对语言水平的懒惰没有帮助。 someFunc(a + b)在JS第一增加的值ab该结果作为参数向someFunc然后供应。Haskell中的等效项不会这样做。如果调用的函数从不使用该值,则它将从不执行加法。如果最终使用它,则将其视为要计算的表达式,直到需要其结果为止。如果您从不执行任何会强制执行的操作(例如IO),则它将永远不会真正执行计算。
Scott Sauyet,2015年

@ScottSauyet也许您可能会争辩说例如可以通过ES6生成器以某种形式使用“惰性评估”-许多JS框架具有“惰性”特征-RxJ,ImmutableJs等
arcseldon 2016年

8
这个答案应该是DrBoolean的书中的一个章节。:)
塞斯(Seth)2013年

1
Ramda文档倾向于使用“列表”作为JS提供的最接近列表的缩写,即密集数组。它们具有与纯列表不同的性能特征,当然还有一些不同的API,但是它们可以用于许多相同的目的,并且它们是Ramda可用的最接近的本机类型(但请参阅github.com/funkia/list)。 API,从概念上讲,它想使用纯列表。我会说不是真的数组,因为C风格的数组不比JS规范,而且没有一个真正的数学数组,但这只是一个小问题。
Scott Sauyet
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.