As an exercise, I tried to construct an infinite, lazy list, recursively, inside a monad.
Basically, the equivalent of nat
, but monadic, monat
:
nat :: Int -> [Int]
nat n = n : nat (n+1)
monat :: Monad m => Int -> m [Int]
monat n = return n >>= \n -> (n:) <$> monat (n+1)
But monat
isn't really lazily evaluated: it's impossible to get the first elements without computing it all:
ghci> take 5 $ nat 0
[0,1,2,3,4]
ghci> take 5 <$> (monat 0) :: Maybe [Int]
... never ending computation ...
I suspect the issue must lie in fmap
or >>=
, since they're the only extra functions I'm using there but not in nat
. However I looked at their implementation and I don't see why or where laziness is broken:
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)
instance Monad Maybe where
(Just x) >>= k = k x
Nothing >>= _ = Nothing
Can you help me understand why the list in
monat
isn't computed lazily?Is there any way to understand why the computation doesn't end, besides analyzing the code? For instance, can I do something like pausing evaluation in GHCi and look at the few latest stack trace frames in order to understand where it's looping? How?