-->

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

2019-05-22 23:37发布

问题:

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.

回答1:

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 compare 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 compared 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 computation. 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.