I'm trying to improve my understanding of Applicatives and Monads by implementing their function instances in Javascript. My knowledge of Haskell is limited and I hope that my question makes sense at all.
Here are my implementations of fmap, <*> and >>= for the Functor, Applicative and Monad typeclasses in Javascript:
const fmap = f => g => x => f(g(x)); // B combinator
const apply = f => g => x => f(x) (g(x)); // S combinator
const bind = f => g => x => g(f(x)) (x); // ?
I am not sure whether bind is the correct translation of the Haskell implementation:
(>>=) :: (r -> a) -> (a -> (r -> b)) -> r -> b
instance Monad ((->) r) where
f >>= k = \ r -> k (f r) r
Provided that bind is correct, how is it interpreted? I know that an Applicative can sequence effectful computations. I also know that a Monad in addition allows you to determine a next effect according to the result of a previous one.
I can see the sequences (eager evaluation order in Javascript):
apply:f(x)...g(x)...lambda(result of g)... result oflambdabind:f(x)...g(result of f)...lambda(x)... result oflambda
However, the bind function looks pretty weird. Why are f and g nested the other way around? How is the specific Monad behavior (determines a next effect according to a previous one) reflected in this implementation? Actually g(f(x)) (x) looks like a function composition with flipped arguments, where g is a binary function.
When I apply apply/bind with an unary and a binary function, they yield the same result. This doesn't make much sense.