我想有一个懒惰生成的随机数列表,我设法做到了,但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
但是,这阻止了您使用传统的列表函数来使用"有效列表";您被推入管道生态系统。
(折叠包中的应用折叠也可用于使用列表,具有impurely
和foldM
辅助功能。
在定义有效列表时,应尽可能多地使用 MonadPlus
接口,如此处所述。它使有效列表与库无关。
更好的方法可能是生成一个种子,然后使用 randoms
计算列表:
randomRsIO :: Random a => (a, a) -> IO [a]
randomRsIO b = do
g <- newStdGen
return $ randomRs b g
或者干脆
randomRsIO b = fmap (randomRs b) newStdGen