如何使用适当的 IO monad 打印无限列表中的每个项目
How can I print every item in an infinite list with proper IO monad
我有一个整数的简单定义,用无限列表完成:
nats = 0: map (+1) nats
我想制作一个打印每个元素的无限列表版本。
我用 Data.Trace (trace)
做到了
nats = 0: map (\x -> 1 + trace (show x) x) nats
不过有点坑爹。
用 IO monad 正确地完成它会更好。
我尝试使用 IO [Int]
类型的无限列表,代码如下:
nats' = (fmap f nats') >>= mapM (\x -> do{print x; return x})
where f l = 0:map (+1) l
类型签名有效,但是当我尝试用 take 10 'nats
评估它时,
它陷入无限递归而没有打印任何东西。
此代码有什么问题,类型签名是否正确以及解决此问题的正确方法是什么?
编辑 :
我有这个问题的一个变体,我想创建一个包含用户所有输入的无限列表。
我该怎么做?
IO monad 是严格的。当我们 运行 x <- ioAction
时,我们完全执行 ioAction
并在 x
绑定到一个值之前观察它的所有副作用。因此,如果 ioAction
是一个无限循环,它永远不会 return 一个值绑定到 x
。
在你的例子中,代码的形式是
nats' = (fmap f nats') >>= ...
相当于
nats' = nats' >>= return . f >>= ...
因此,nats'
会在执行return . f
之前递归,导致无限循环并阻止任何输出。
如何让它真正发挥作用?
最惯用的Haskell方法是将副作用与实际计算分开:我们定义一个纯值
nats = 0 : map (+1) nats
我们打印它
nats' = for_ nats print
请注意,上面使用 for
/traverse
/mapM
(而不是它们的 _
变体)没有什么意义,因为列表是无限的,所以它永远不会 return 一个值,只会执行无限次打印。
如果你真的想交织 IO 和计算,即使这通常不那么惯用,你也可以使用递归:
nats' = go 0
where go l = print l >>= go (l+1)
如果你想尝试 return 列表,即使那实际上永远不会发生,你可以使用这个:
nats' = go 0
where go l = do
print l
ls <- go (l+1)
return (l:ls)
然而,这太复杂了。
我有一个整数的简单定义,用无限列表完成:
nats = 0: map (+1) nats
我想制作一个打印每个元素的无限列表版本。
我用 Data.Trace (trace)
nats = 0: map (\x -> 1 + trace (show x) x) nats
不过有点坑爹。 用 IO monad 正确地完成它会更好。
我尝试使用 IO [Int]
类型的无限列表,代码如下:
nats' = (fmap f nats') >>= mapM (\x -> do{print x; return x})
where f l = 0:map (+1) l
类型签名有效,但是当我尝试用 take 10 'nats
评估它时,
它陷入无限递归而没有打印任何东西。
此代码有什么问题,类型签名是否正确以及解决此问题的正确方法是什么?
编辑 :我有这个问题的一个变体,我想创建一个包含用户所有输入的无限列表。 我该怎么做?
IO monad 是严格的。当我们 运行 x <- ioAction
时,我们完全执行 ioAction
并在 x
绑定到一个值之前观察它的所有副作用。因此,如果 ioAction
是一个无限循环,它永远不会 return 一个值绑定到 x
。
在你的例子中,代码的形式是
nats' = (fmap f nats') >>= ...
相当于
nats' = nats' >>= return . f >>= ...
因此,nats'
会在执行return . f
之前递归,导致无限循环并阻止任何输出。
如何让它真正发挥作用?
最惯用的Haskell方法是将副作用与实际计算分开:我们定义一个纯值
nats = 0 : map (+1) nats
我们打印它
nats' = for_ nats print
请注意,上面使用 for
/traverse
/mapM
(而不是它们的 _
变体)没有什么意义,因为列表是无限的,所以它永远不会 return 一个值,只会执行无限次打印。
如果你真的想交织 IO 和计算,即使这通常不那么惯用,你也可以使用递归:
nats' = go 0
where go l = print l >>= go (l+1)
如果你想尝试 return 列表,即使那实际上永远不会发生,你可以使用这个:
nats' = go 0
where go l = do
print l
ls <- go (l+1)
return (l:ls)
然而,这太复杂了。