有没有安全的方法可以在IO中生成惰性列表



我想有一个懒惰生成的随机数列表,我设法做到了,但unsafeInterleaveIO

rs :: Random a => (a,a) -> IO [a]
rs b = do
  r <- randomRIO b
  ns <- unsafeInterleaveIO $ rs b
  return (r:ns)

有没有安全的方法来实现这种价值观?

如果你想要"延迟生成的具有效果的元素",一种解决方案是避开传统的列表类型,并使用 List monad 转换器,就像管道库中的ListT

import System.Random
import Control.Monad
import Pipes
import qualified Pipes.Prelude as P
rs :: rs :: (Random a, MonadPlus m, MonadIO m) => (a,a) -> m a
rs b = liftIO (randomRIO b) `mplus` rs b
main :: IO ()
main = runEffect $ enumerate (rs (1::Int,10)) >-> P.take 5 >-> P.print

结果是:

*Main> :main
7
2
5
6
4

但是,这阻止了您使用传统的列表函数来使用"有效列表";您被推入管道生态系统。

(折叠包中的应用折叠也可用于使用列表,具有impurelyfoldM辅助功能。

在定义有效列表时,应尽可能多地使用 MonadPlus 接口,如此处所述。它使有效列表与库无关。

更好的方法可能是生成一个种子,然后使用 randoms 计算列表:

randomRsIO :: Random a => (a, a) -> IO [a]
randomRsIO b = do
    g <- newStdGen
    return $ randomRs b g

或者干脆

randomRsIO b = fmap (randomRs b) newStdGen

最新更新