When compiling the function below:
myJoin :: Monad m => m (m a) -> m a myJoin mma = do ma <- mma a <- ma return a
ghc generates two calls to the bind function (just as the code specifies). But this function is (I believe) semantically equivalent to the following:
myJoin' :: Monad m => m (m a) -> m a myJoin' mma = do ma <- mma ma
which could potentially be more efficient since only one bind is performed. Perhaps ghc could be taught to perform this transformation.
For an even simpler example consider:
silly_1 :: Monad m => m a -> m a silly_1 ma = do a <- ma return a silly_2 :: Monad m => m a -> m a silly_2 ma = do ma silly_3 :: Monad m => m a -> m a silly_3 ma = ma
Here ghc realizes that (2) and (3) are the same function (aka the identity function) but it compiles (1) with a call to bind.
silly_1 = \ (@ (m_a76C :: * -> *)) (@ a_a76D) ($dMonad_a76F :: Monad m_a76C) (ma_a5Vu :: m_a76C a_a76D) -> >>= @ m_a76C $dMonad_a76F @ a_a76D @ a_a76D ma_a5Vu (\ (a1_a5Vv :: a_a76D) -> return @ m_a76C $dMonad_a76F @ a_a76D a1_a5Vv) silly_2 = \ (@ (m_ankf :: * -> *)) (@ a_ankg) _ [Occ=Dead] (ma_an0P :: m_ankf a_ankg) -> ma_an0P silly_3 = silly_2
This is all with ghc 8.8.4.
Teach ghc to perform this transformation.