我希望有一个懒惰生成的随机数列表,我设法用unsafeInterleaveIO
做到了:
rs :: Random a => (a,a) -> IO [a]
rs b = do
r <- randomRIO b
ns <- unsafeInterleaveIO $ rs b
return (r:ns)
是否有安全方式来实现这种值?
答案 0 :(得分:5)
如果你想要“延迟生成带有效果的元素”,一种解决方案是避开常规列表类型并使用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
但是,这会阻止您使用传统的列表函数来使用“有效列表”;你被推入管道生态系统。
(来自foldl包的应用折叠也可用于使用impurely
和foldM
辅助功能来使用列表。)
在定义有效列表时,应尽可能使用MonadPlus
接口,如here所述。它使有效列表更加与库无关。
答案 1 :(得分:3)
更好的方法可能是生成种子,然后使用randoms
计算列表:
randomRsIO :: Random a => (a, a) -> IO [a]
randomRsIO b = do
g <- newStdGen
return $ randomRs b g
或者只是
randomRsIO b = fmap (randomRs b) newStdGen