The IO monad is strict. When we run x <- ioAction
, we fully execute ioAction
and observe all its side effects before x
is bound to a value. Consequently, if ioAction
is an infinite loop, it will never return a value to be bound to to x
.
In your case, the code has the form
nats' = (fmap f nats') >>= ...
which is equivalent to
nats' = nats' >>= return . f >>= ...
So, nats'
will recurse before executing return . f
, causing an infinite loop and preventing any output.
How to make this actually work?
The most idiomatic Haskell way is to separate side effects from actual computation: we define a pure value
nats = 0 : map (+1) nats
and the we print it
nats' = for_ nats print
Note that above there is little point to use for
/traverse
/mapM
(instead of their _
variants), since the list is infinite so it will never return a value, but only perform infinitely many prints.
If you really want to interleave IO and computation, even if that's usually less idiomatic, you can use recursion:
nats' = go 0
where go l = print l >>= go (l+1)
If you want to try returning a list anyways, even if that will actually never happen, you can use this:
nats' = go 0
where go l = do
print l
ls <- go (l+1)
return (l:ls)
However, this is unnecessarily complex.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…