ramda.js 中 chain() 和 map() 之间的区别

difference between chain() and map() in ramda.js

chain()(来自 ramda 包)和 Javascript 中的 map() 有什么区别?

在这两个函数中,程序员输入一个对象和一些 lambda/function 并对其进行一定的计算。谢谢

抽象类型

chainmap 每个都对抽象类型进行操作。 map 对任何 Functor. This is any item with a map function that obeys certain laws. chain operates on a Chain 元素进行操作。同样,这是具有合法chain功能的东西,以及具有合法applymap功能的东西。

Ramda 提供 mapchain 函数,这些函数将与满足这些契约的类型一起工作。它还提供某些内置类型的实现(map 的函数、数组和对象以及 chain 的函数和数组。)

要了解它们有何不同,比较它们的签名就足够简单了:

// map   :: Functor f => (a → b)   → f a → f b
// chain :: Chain   m => (a → m b) → m a → m b

你可以这样想:提供给 map 的函数接受一个类型 A 和 returns 一个类型 B。map 接受那个函数和一个容器holding type A and returns a container holding type B. 相比之下,提供给 chain 的函数采用类型 A 和 returns a container持有类型 B。chain 接受该函数和持有类型 A 的容器,返回持有类型 B 的容器。

你可以认为 chainmap 相比解开一层容器。

一些例子

例如,假设我们有一个函数 factors,它 returns 一个整数的因子(例如 factors(14) //=> [1, 2, 7, 14]。)下面是如何 map并且 chain 可以处理数字列表:

map(factors, [12, 15])   //=> [[1, 2, 3, 4, 6, 12], [1, 3, 5, 15]]
chain(factors, [12, 15]) //=> [1, 2, 3, 4, 6, 12, 1, 3, 5, 15]

或者如果我们有一个 Maybe 类型用于简化空值处理,子类型 Just 表示一个值,Nothing 表示计算中的一些空值。我们可以编写一个安全的平方根函数,例如

const sqrt = (n) => n > 0 ? Just(Math.sqrt(n)) : Nothing()

然后我们看到 mapchain 之间的这些差异。

map(sqrt, Just(25)) //=> Just(Just(5))
chain(sqrt, Just(25)) //=> Just(5)

map(sqrt, Just(-25)) //=> Just(Nothing)
chain(sqrt, Just(-25)) //=> Nothing

最后,对于函数,由于

中所述的原因
map(f, g)   //~> x => f(g(x));
chain(f, g) //~> x => f(g(x))(x); 

总结

从他们的签名可以看出,mapchain之间存在某种关系,但它们是不同的功能,用于非常不同的目的。 chain 与有时称为 flatMap 的内容有关,因为它使 map.

创建的那种结果变平(一级)

但思考它们的最佳方式是查看与这些函数相关的签名和法则。

2019 年 8 月更新

完全同意 Scott 的回答 ;) 希望通过比较添加一个简单示例。假设您有一群朋友,他们都有几种最喜欢的食物。我们可以使用 chain(又名 flatMap)来创建一个数组,其中包含您应该在下一次聚会上提供的所有食物。

import * as R from "ramda";

const friends = [
  {
    name: "Jill",
    favoriteFoods: ["pizza", "hummus"]
  },
  {
    name: "Bob",
    favoriteFoods: ["ice cream"]
  },
  {
    name: "Alice",
    favoriteFoods: ["chicken wings", "salmon"]
  }
];

let favouriteFoods = R.map(friend => friend.favoriteFoods);

console.log(favouriteFoods(friends));
//-> [ [ 'pizza', 'hummus' ], [ 'ice cream' ], [ 'chicken wings', 'salmon' ] ]



favouriteFoods = R.chain(friend => friend.favoriteFoods);

console.log(favouriteFoods(friends));
//-> [ 'pizza', 'hummus', 'ice cream', 'chicken wings', 'salmon' ]

一种常见的模式是将展平函数与映射函数结合起来。您可以分两步显式映射然后展平。然而,Chain 可以为您做到这两点。