mostly-adequate-guide icon indicating copy to clipboard operation
mostly-adequate-guide copied to clipboard

Ch2: First Class Functions

Open granthusbands opened this issue 7 years ago • 4 comments

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.

granthusbands avatar Oct 05 '18 20:10 granthusbands

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.

HoverBaum avatar Oct 11 '18 08:10 HoverBaum

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:

KtorZ avatar Oct 11 '18 08:10 KtorZ

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.

granthusbands avatar Oct 11 '18 12:10 granthusbands

My opinion

  1. 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).
  2. We also should not treat Array.prototype.map as 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:

map similarly uses type variables, but this time we introduce b which may or may not be the same type as a. We can read it as: map takes a function from any type a to the same or different type b, then takes an array of a's and results in an array of b'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 a to b, an array of a, and it delivers us an array of b. The only sensible thing for it to do is call the bloody function on each a. 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 by f only when f is nullary or unary (which means that it expects not more than 1 argument)

vladimirlogachev avatar Mar 08 '19 20:03 vladimirlogachev