首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Rand monad的MonadFix实例

Rand monad的MonadFix实例
EN

Stack Overflow用户
提问于 2011-03-20 06:15:50
回答 3查看 464关注 0票数 4

我想用System.Random.MWC.Monad的Rand monad生成无限的数字流。如果这个monad有一个MonadFix实例就好了,或者像这样的实例:

代码语言:javascript
复制
instance (PrimMonad m) => MonadFix m where
     ...

然后可以这样写:

代码语言:javascript
复制
runWithSystemRandom (mfix (\ xs -> uniform >>= \x -> return (x:xs)))

不过,没有一个。

我正在使用MonadFix docs,但我看不到实现此实例的明显方法。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-03-22 02:34:59

一个问题:你希望如何生成你的初始种子?

问题是,MWS是建立在“原始”包上的,它只抽象IO和严格(Control.Monad.ST.ST )。它也不抽象惰性(Control.Monad.ST.Lazy.ST s)。

也许可以为"primitive“创建实例来覆盖lazy ST,然后MWS就可以是惰性的了。

更新:我可以通过使用strictToLazyST使用Control.Monad.ST.Lazy来实现这一点:

代码语言:javascript
复制
module Main where

import Control.Monad(replicateM)
import qualified Control.Monad.ST as S
import qualified Control.Monad.ST.Lazy as L
import qualified System.Random.MWC as A

foo :: Int -> L.ST s [Int]
foo i = do rest <- foo $! succ i
           return (i:rest)

splam :: A.Gen s -> S.ST s Int
splam = A.uniformR (0,100)

getS :: Int -> S.ST s [Int]
getS n = do gen <- A.create
            replicateM n (splam gen)

getL :: Int -> L.ST s [Int]
getL n = do gen <- createLazy
            replicateM n (L.strictToLazyST (splam gen))

createLazy :: L.ST s (A.Gen s)
createLazy = L.strictToLazyST A.create

makeLots :: A.Gen s -> L.ST s [Int]
makeLots gen = do x <- L.strictToLazyST (A.uniformR (0,100) gen)
                  rest <- makeLots gen
                  return (x:rest)

main = do
  print (S.runST (getS 8))
  print (L.runST (getL 8))
  let inf = L.runST (foo 0) :: [Int]
  print (take 10 inf)
  let inf3 = L.runST (createLazy >>= makeLots) :: [Int]
  print (take 10 inf3)
票数 3
EN

Stack Overflow用户

发布于 2011-03-20 09:50:15

您可以编写MonadFix实例。但是,该代码不会生成不同的随机数的无限流。mfix的参数是一个只调用uniform一次的函数。当代码运行时,它将恰好调用uniform一次,并创建一个包含结果的无限列表。

您可以尝试等效的IO代码,看看会发生什么:

代码语言:javascript
复制
import System.Random
import Control.Monad.Fix
main = print . take 10 =<< mfix (\xs -> randomIO >>= (\x -> return (x : xs :: [Int])))

您似乎希望使用有状态随机数生成器,并且希望运行生成器并懒惰地收集其结果。如果不小心使用unsafePerformIO,这是不可能的。除非您需要快速生成许多随机数,否则可以使用纯RNG函数,如randomRs

票数 6
EN

Stack Overflow用户

发布于 2014-09-14 15:32:52

(这将更适合作为散热器的答案的注释,但它有点太长了。)

MonadFix实例必须遵守several laws。其中一个正在收缩/变粗。

代码语言:javascript
复制
mfix (\x -> a >>= \y -> f x y)  =  a >>= \y -> mfix (\x -> f x y)

这条法律允许将表达式重写为

代码语言:javascript
复制
mfix (\xs -> uniform >>= \x -> return (x:xs))
= uniform >>= \x -> mfix (\xs -> return (x:xs))
= uniform >>= \x -> mfix (return . (x :))

使用另一个定律purity mfix (return . h) = return (fix h),我们可以进一步简化为

代码语言:javascript
复制
= uniform >>= \x -> return (fix (x :))

并使用标准的单元律并将fix (x :)重写为repeat x

代码语言:javascript
复制
= liftM (\x -> fix (x :)) uniform
= liftM repeat uniform

因此,结果确实是一次调用uniform,然后无限地重复单个值。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5365292

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档