MostlyAdequate / mostly-adequate-guide

Mostly adequate guide to FP (in javascript)
Other
23.43k stars 1.87k forks source link

Apply.ap() looks incorrect (?) #579

Closed manuscriptmastr closed 4 years ago

manuscriptmastr commented 4 years ago

Hello FP friends! I am using this book as a "sanity check" for an FP workshop at my company.

I noticed that in the Appendix and any examples with .ap(), the first container holds a function while .ap() passes it a container with any value. This appears to be opposite of the Fantasy-land specification, where the content of .ap() must be a container with a function. Otherwise the law of composition fails.

import R from 'ramda';

// Mostly Adequate Guide, Appendix B:
class Identity {
...
ap: other => other.map(this.value)
...
}
Identity(R.add).ap(Identity(1)).ap(Identity(2)) // Identity(3)

// Fantasy-Land/Sanctuary-Identity:
class Identity {
...
ap: other => other.value(this.value)
...
}
Identity(1).ap(Identity(R.add(2))).ap(Identity(R.add(3)) // Identity(6)

// Law of composition:
Identity(1).ap(Identity(R.add(2)).ap(Identity(R.add(3)).map(f => g => x => f(g(x))))) // Identity(6)
// Is equivalent to
Identity(1).ap(Identity(R.add(2))).ap(Identity(R.add(3))) // Identity(6)

I am fairly new to containers — am I lying here 😄? (This difference is also the case with Task and possibly other containers in the Appendix)

See:

KtorZ commented 4 years ago

Indeed, the arguments are swapped compared to fantasy-land. Mostly adequate ap follows the following signature:

ap :: f (a -> b) -> f a -> f b

where the first argument is implicitly this.

There's nothing incorrect per se about it, it is just different from what fantasy-land specifies, like several other thing in the book currently. We discussed in the past about whether or not the book should follow the specs from fantasy-land; yet the book isn't about fantasy-land, it's about FP in general, and some concepts are better taught in a way that sometimes differ from fantasy-land (this one is an example, I do prefer the way ap is defined in the mostly-adequate guide for it is easier to reason about it).

I hope this answers your concerns :blush:

(note: in Haskell for example, ap is commonly defined similarly to what's in the appendix https://hoogle.haskell.org/?hoogle=ap)

manuscriptmastr commented 4 years ago

@KtorZ Thanks for the clarification! I didn't realize there was more than one way to define these behaviors 🤷‍♂️.