Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
302 views
in Technique[技术] by (71.8m points)

haskell - How can I print every item in an infinite list with proper IO monad

I have this simple definition of the integers, done with an infinite list:

nats = 0: map (+1) nats

And I would like to make a version of that infinite list that print every element.

I did it with Data.Trace (trace)

nats = 0: map (x -> 1 + trace (show x) x) nats

But it's a bit cheating. It would be nicer to do it properly with the IO monad.

I tried to do it with an infinite list of type IO [Int] with the following code:

nats' = (fmap f nats') >>= mapM (x -> do{print x; return x})
  where f l = 0:map (+1) l

The type signatures work, but however when I try to evaluate it with take 10 'nats, it gets stuck in an infinite recursion without printing anything.

What is wrong with this code, is the type signature right and what would be the right way to approach this problem?

EDIT :

I have a variant of this problem where I want to create an infinite list containing all the inputs of the user. How can I do that?

question from:https://stackoverflow.com/questions/65640840/how-can-i-print-every-item-in-an-infinite-list-with-proper-io-monad

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...