MostlyAdequate / mostly-adequate-guide

Mostly adequate guide to FP (in javascript)
Other
23.39k stars 1.86k forks source link

Some suggestions #255

Open ccorcos opened 8 years ago

ccorcos commented 8 years ago

Ch 9

You jump into this section a little quickly -- could use some explanation.

Now, I've seen these laws, identity and associativity, somewhere before... Hold on, I'm thinking...Yes of course! They are the laws for a category. But that would mean we need a composition function to complete the definition. Behold:

var mcompose = function(f, g) { return compose(chain(f), chain(g)); };

// left identity mcompose(M, f) == f;

// right identity mcompose(f, M) == f;

// associativity mcompose(mcompose(f, g), h) === mcompose(f, mcompose(g, h));

We have never talked about these laws before or what mcompose even is. This came out of no where and I had/have no idea what this means. What is f, g, M, h? Are those monads? I'm so lost.

Ch 10

When talking about using ap to apply tasks to renderPage:

Both Http calls will happen instantly and renderPage will be called when both are resolved.

I was very confused how this happens. I looked into data.task from folktale and I see that:

Task.prototype.ap = function _ap(f2) {
  return this.chain(function(f) {
    return f2.map(f);
  });
};

So ap is using chain. And chain runs in sequence:

Task.prototype.chain = function _chain(f) {
  var fork = this.fork;
  var cleanup = this.cleanup;

  return new Task(function(reject, resolve) {
    return fork(function(a) {
      return reject(a);
    }, function(b) {
      return f(b).fork(reject, resolve);
    });
  }, cleanup);
};

It was totally a mindfuck and probably a good experience trying to figure this all out -- but my point is that I don't think this actually runs in parallel. If it does, could you explain in more detail how that actually works?

Also, you talk about how ap must always return the same type here:

liftA2(_.concat, tOfM('Rainy Days and Mondays'), tOfM(' always get me down'));

How the hells does concat get down the string? Shouldnt it be trying to concat two maybes and throw and error? thats not going to work... How does this actually end up working?

And lastly:

Though we could already do so with monads, we should prefer applicative functors when we aren't in need of monadic specific functionality.

Why? What's a single applicative functor that isn't a monad?

Great book -- I read it all in one day :)

DrBoolean commented 8 years ago

Hi Chet,

Thanks for the feedback!

I agree that Ch9 could use some clarification.

The Task applicative instance has been rewritten and currently is sitting in a PR. That will make it run concurrently rather than wait.

The liftA2(concat was updated some time ago to read liftA2(liftA2(concat, which is a ridiculously complex example to demonstrate this. But that would crack both Task and Maybe open to concat the Strings. Interestingly, Maybe can have a semigroup instance that concats whatever its holding so long as what it holds is also a semigroup. I believe the Task implementation should be updated to that as well so concat should just keep combining things all the way down.

A good applicative functor that isn't a monad is a ZipList. ZipList([f,g,h]).ap(ZipList([x,y,z])) will equal ZipList([f(x), g(y), h(z)])

DrBoolean commented 8 years ago

I should update that last part to read: "Though we could already do so with monads, we should prefer the applicative functor instance when we aren't in need of monadic specific functionality." Essentially use ap instead of chain

ccorcos commented 8 years ago

Interestingly, Maybe can have a semigroup instance that concats whatever its holding so long as what it holds is also a semigroup

interesting... makes sense though.

A good applicative functor that isn't a monad is a ZipList.

A ZipList could have concat and empty though right?

DrBoolean commented 8 years ago

I believe so, but to be clear we're talking about applicative functors that aren't monads with ZipList and monoids with concat so this example is double confusing

char0n commented 7 years ago

Just bumped to CH9 and mcompose. To me and others, this section may seem confusing and the closes explanation I could find is here

// left identity
mcompose(M, f) == f;

// right identity
mcompose(f, M) == f;

@DrBoolean I am right to assume that by M you mean function that returns monadic type ? Thanks for clarifing this issue