I like to think of a Monad in terms of the Monad laws, it makes it much less abstract. https://www.haskell.org/haskellwiki/Monad_laws
Different monads can have drastically different implementations but they should all obey those laws.
Different monads can have drastically different implementations but they should all obey those laws.
I understood the mondas in terms of javascript, as it is written over here: https://blog.jcoglan.com/2011/03/05/translation-from-haskell...
[Edit: And if the implementing pieces are named correctly.]
M1: return a >>= f = f a
M2: m >>= return = m
M3: (m >>= f) >>= g = m >>= (\ x -> f x >>= g)
(fmap f . fmap g) m = (fmap f . fmap g) m
by defn of (.) = fmap f (fmap g m)
by defn of fmap = fmap f (m >>= return . g)
by defn of fmap = (m >>= return . g) >>= return . f
by M3 = m >>= (\ x -> (return . g) x >>= return . f)
by defn of (.) = m >>= (\ x -> return (g x) >>= return . f)
by M1 = m >>= (\ x -> (return . f) (g x))
by defn of (.) = m >>= (\ x -> return (f (g x)))
by defn of (.) = m >>= (\ x -> (return . (f . g)) x)
eta reduction = m >>= return . (f . g)
by defn of fmap = fmap (f . g) m
(fmap f . fmap g) m = fmap (f . g) m