ramda.js 中 chain() 和 map() 之间的区别
difference between chain() and map() in ramda.js
chain()
(来自 ramda
包)和 Javascript 中的 map()
有什么区别?
在这两个函数中,程序员输入一个对象和一些 lambda/function 并对其进行一定的计算。谢谢
抽象类型
chain
和 map
每个都对抽象类型进行操作。 map
对任何 Functor. This is any item with a map
function that obeys certain laws. chain
operates on a Chain 元素进行操作。同样,这是具有合法chain
功能的东西,以及具有合法apply
和map
功能的东西。
Ramda 提供 map
和 chain
函数,这些函数将与满足这些契约的类型一起工作。它还提供某些内置类型的实现(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 的容器。
你可以认为 chain
与 map
相比解开一层容器。
一些例子
例如,假设我们有一个函数 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()
然后我们看到 map
和 chain
之间的这些差异。
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);
总结
从他们的签名可以看出,map
和chain
之间存在某种关系,但它们是不同的功能,用于非常不同的目的。 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 可以为您做到这两点。
chain()
(来自 ramda
包)和 Javascript 中的 map()
有什么区别?
在这两个函数中,程序员输入一个对象和一些 lambda/function 并对其进行一定的计算。谢谢
抽象类型
chain
和 map
每个都对抽象类型进行操作。 map
对任何 Functor. This is any item with a map
function that obeys certain laws. chain
operates on a Chain 元素进行操作。同样,这是具有合法chain
功能的东西,以及具有合法apply
和map
功能的东西。
Ramda 提供 map
和 chain
函数,这些函数将与满足这些契约的类型一起工作。它还提供某些内置类型的实现(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 的容器。
你可以认为 chain
与 map
相比解开一层容器。
一些例子
例如,假设我们有一个函数 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()
然后我们看到 map
和 chain
之间的这些差异。
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);
总结
从他们的签名可以看出,map
和chain
之间存在某种关系,但它们是不同的功能,用于非常不同的目的。 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 可以为您做到这两点。