3

I'm having trouble understanding the signature of Ramda docs. For example if you look at map you see this

Functor f => (a → b) → f a → f b

I don't see how this pattern fits the example:

var double = x => x * 2;

R.map(double, [1, 2, 3]); //=> [2, 4, 6]

The functor in this example is [1,2,3], so how does that get placed into the signature of f in Functor f => (a → b) → f a → f b? Also, what do the mean?

Mogsdad
  • 44,709
  • 21
  • 151
  • 275
stackjlei
  • 9,485
  • 18
  • 65
  • 113

1 Answers1

4

I'll give a brief answer here, but a more complete one is spread across two answers to a similar question, which in turn was taken from the Ramda wiki page. (Disclaimer: I'm the author of that page and one of the principals in Ramda itself.)

This is broken into two parts:

Functor f => (a → b) → f a → f b

Before the fat arrow (=>) we have constraints on the remainder. The single constraint in this example is that the variable f must be a Functor. A Functor is a type whose members have a map method which obeys certain laws. And the declaration is parameterized over another type, so we don't write just f but f String, f Number, or more generically, f a for some unknown type a.

The skinny arrow (->) is an abbreviation for the type Function. So instead of writing

Function x y

we can instead write

x -> y

or when needed to avoid ambiguity.

(x -> y)

Putting these together, we can note that in R.map(double, [1, 2, 3]), we have a function (double) from Number to Number, which means that our a and b are both Number. And our functor is Array. So specializing the definitions with these types, we have map accepting a function from Number to Number, and returning a function that takes an array of Numbers and returns a new array of Numbers. (That's because in this system, -> binds to the right, so (a -> b -> c) is equivalent to (a -> (b -> c)). In Ramda, all functions are curried in such a way that you can call them with any initial set of parameters, and until all the terms have been supplied, you continue to get back functions. Thus with Ramda functions there is no real difference between R.map(double)([1, 2, 3]) and R.map(double, [1, 2, 3]).

Community
  • 1
  • 1
Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
  • Is `Function x y` just the same as `function x ( ) {y}`? – stackjlei Apr 17 '17 at 00:02
  • 1
    No, `Function x y`, and its shorthand `x -> y`, represent a function that accepts a parameter of type `x` and returns one of type `y`. `function(str) {return str.length;}` has type `Function String Int` or more concisely, `String -> Int`. – Scott Sauyet Apr 17 '17 at 02:47
  • 1
    Why does propEq have the signature of `String → a → Object → Boolean` when it accepts 2 strings as an argument and returns a boolean? Shouldn't it be `string, string` -> boolean`? – stackjlei Jun 19 '17 at 23:49
  • 1
    `propEq('foo', 42, {foo: 42, bar: 52}) //=> true`. And `propEq('foo', 42, {foo: 52, bar: 42}) //=> false`. The first argument has to be a String (although perhaps it should extend to also allow Symbols). The second argument is of arbitrary type (here a number, but anything is allowable.) The third must be an object. It returns a boolean. That signature looks correct. – Scott Sauyet Jun 20 '17 at 01:26
  • 1
    How do I know what is finally being returned? In the example before you mentioned that `->` binds right so `(a -> b -> c)` is equivalent to `(a -> (b -> c))`, but for propEq it seems like `String → a → Object → Boolean` is equivalent to `(String → a → Object) → Boolean` – stackjlei Jun 20 '17 at 05:05
  • 1
    Ramda's version of curry in means that these are all equivalent : `propEq('x') (42)(obj)`, `propEq('x')(42, obj) `, `propEq('x', 42) (obj)`, and `propEq('x', 42, obj)`. All the intermediate forms are (curried) functions. If the final output is also a function, it would be wrapped in parentheses: `comp :: (b -> c) -> (a -> b) -> (a -> c)` takes two functions and returns a third. – Scott Sauyet Jun 20 '17 at 10:33
  • 1
    As to what's finally being returned, perhaps the easiest way to state it is that it's what's to the right of the last arrow not contained in parentheses. – Scott Sauyet Jun 20 '17 at 10:35