admin管理员组

文章数量:1279185

What is the difference between chain() (from ramda package) and map() in Javascript?

In both functions the programmer inputs an object and some lambda/function and gets a certain calculation of it. Thanks.

What is the difference between chain() (from ramda package) and map() in Javascript?

In both functions the programmer inputs an object and some lambda/function and gets a certain calculation of it. Thanks.

Share Improve this question edited Jul 27, 2018 at 21:47 James Conkling 3,6634 gold badges26 silver badges37 bronze badges asked Apr 16, 2018 at 15:44 J. DoeJ. Doe 958 bronze badges 7
  • 2 chain isn't a native JS method on the Array.prototype – Sterling Archer Commented Apr 16, 2018 at 15:45
  • chain is from ramda – J. Doe Commented Apr 16, 2018 at 15:45
  • Can you edit your question with that knowledge and tag so that people aren't confused, please? – Sterling Archer Commented Apr 16, 2018 at 15:46
  • @SterlingArcher I understand. But except for it, are these functions equivalent? – J. Doe Commented Apr 16, 2018 at 15:47
  • 2 According to the documentation no. "chain maps a function over a list and concatenates the results. chain is also known as flatMap in some libraries" – Sterling Archer Commented Apr 16, 2018 at 15:48
 |  Show 2 more ments

2 Answers 2

Reset to default 14

Abstract Types

chain and map each operate on an abstract type. map operates on any Functor. This is any item with a map function that obeys certain laws. chain operates on a Chain element. Similarly, this is something with a lawful chain function, as well as having lawful apply and map functions.

Ramda provides map and chain functions that will work with types fulfilling these contracts. It also supplies implementation for certain built-in types (functions, arrays, and objects for map and functions and arrays for chain.)

To see how they differ, it's simple enough to pare their signatures:

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

You can think about it like this: the function supplied to map takes an item of type A and returns one of type B. map accepts that function and a container holding type A and returns a container holding type B. The function supplied to chain by contrast takes an item of type A and returns a container holding type B. chain accepts that function and a container holding type A, returning a container holding type B.

You can think about it as though chain unwraps one level of containers pared to map.

Some Examples

For example, let's say we had a function factors, which returns the factors of an integer (factors(14) //=> [1, 2, 7, 14], for instance.) Here is how map and chain would work on a list of numbers:

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]

Or if we had a Maybe type used to simplify null-handling with the subtypes Just to signify a value and Nothing to signify some null in the putation. We might write a safe square root function such as

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

Then we see these differences between map and 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

And finally, for functions, for reasons described in another SO answer,

map(f, g)   //~> x => f(g(x));
chain(f, g) //~> x => f(g(x))(x); 

Summary

You can see from their signatures, that there is some relationship between map and chain, but they are distinct functions, used for very different purposes. chain is related to what is sometimes called flatMap, as it flattens out (one level) of the sort of result created by map.

But the best way to think about them is to look at the signatures and the laws tied to these functions.

Update August 2019

Agree entirely with Scott's answer ;) Wished to add a simple example by way of parison. Let’s say you had a collection of friends who all had several favourite foods. We can use chain (aka flatMap) to create an array of all the foods you should serve at your next party.

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' ]

A mon pattern is to bine a flattening function with a mapping one. You could explicitly map then flatten in 2 separate steps. Chain, however, does both for you.

本文标签: javascriptdifference between chain() and map() in ramdajsStack Overflow