Ch2: First Class Functions
So this chapter is completely ignoring arity. Often, a => fn(a) is entirely valid. A common example is parseInt. myArr.map(parseInt) and myArr.map(s=>parseInt(s)) have entirely different results (being [1, NaN, NaN] and [1,2,3] given ['1','2','3']). I don't know how to correct it cleanly, so I'm just raising this issue.
First of, here is a post explaining the above for people who, like me, wondered about what that was doing: https://wsvincent.com/javascript-parseint-map/
Equipped with that knowledge I think this is a topic in itself. It is more about the implementation details of Array.map and ParseInt in JavaScript.
You could also do:
const parseBase10 = s => parseInt(s, 10)
['1','2','3'].map(parseBase10)
// or even
['1','2','3'].map(Number)
This would create a function to implemented the expected behavior we are looking for or use Number which is a build in function providing this by only taking the first argument from map.
Thus to me it feels more like mentioning quirks in JavaScript that can at first throw you off while going functional is a super valid point but the contents of Chapter 2 is fine in arguing that you can often times replace handing arguments around with just assigning functions.
I like this parseIntBase10 helper which leaves the ambiguity out. I am considering adding this to the appendix and update references of it in the code :+1:
parseInt is an example that was easy to find on the internet. I've hit others, when using promises and when using jQuery, as my natural coding style doesn't introduce apparently unnecessary lambdas. In essence, if the function accepts extra parameters and the caller might give them, then there's potential confusion.
My opinion
- We should not update example code to conform variadic functions and treat them as normal thing in functional world (first, because they can not be safely curried, and second, because we can not say that variadic function is a morphism).
- We also should not treat
Array.prototype.mapas a normal map, because it is doing more than applying a function (it can even mutate third argument!)
const arr = ['a', 'b', 'c'];
arr.map((x, i, xs) => {
xs[0]='wat';
return x;
}); // ["a", "b", "c"]
arr; // ["wat", "b", "c"]
Chapter 07 states:
mapsimilarly uses type variables, but this time we introducebwhich may or may not be the same type asa. We can read it as:maptakes a function from any typeato the same or different typeb, then takes an array ofa's and results in an array ofb's.
Hopefully, you've been overcome by the expressive beauty in this type signature. It literally tells us what the function does almost word for word. It's given a function from
atob, an array ofa, and it delivers us an array ofb. The only sensible thing for it to do is call the bloody function on eacha. Anything else would be a bold face lie.
So we should be consistent about that.
What we should do is to add a single comment:
x => f(x)can be safely replaced byfonly whenfis nullary or unary (which means that it expects not more than 1 argument)