我试图根据数字类编写一个随机数生成器实现。我还添加了Monad和MonadPlus实例。
“MonadPlus”是什么意思以及我添加此实例的原因?因为我想使用这里的守卫:
-- test.hs --
import RandomMonad
import Control.Monad
import System.Random
x = Rand (randomR (1 ::Integer, 3)) ::Rand StdGen Integer
y = do
a <-x
guard (a /=2)
guard (a /=1)
return a
这里有RandomMonad.hs文件内容:
-- RandomMonad.hs --
module RandomMonad where
import Control.Monad
import System.Random
import Data.List
data RandomGen g => Rand g a = Rand (g ->(a,g)) | RandZero
instance (Show g, RandomGen g) => Monad (Rand g)
where
return x = Rand (\g ->(x,g))
(RandZero)>>= _ = RandZero
(Rand argTransformer)>>=(parametricRandom) = Rand funTransformer
where
funTransformer g | isZero x = funTransformer g1
| otherwise = (getRandom x g1,getGen x g1)
where
x = parametricRandom val
(val,g1) = argTransformer g
isZero RandZero = True
isZero _ = False
instance (Show g, RandomGen g) => MonadPlus (Rand g)
where
mzero = RandZero
RandZero `mplus` x = x
x `mplus` RandZero = x
x `mplus` y = x
getRandom :: RandomGen g => Rand g a ->g ->a
getRandom (Rand f) g = (fst (f g))
getGen :: RandomGen g => Rand g a ->g -> g
getGen (Rand f) g = snd (f g)
当我运行ghci解释器时,并给出以下命令
getRandom y (mkStdGen 2000000000)
我可以在计算机上看到内存溢出(1G)。这是不期望的,如果我删除一个后卫,它的工作速度非常快。为什么在这种情况下它的工作太慢了?
我做错了什么?
答案 0 :(得分:3)
你对(>>=)
的定义肯定是错的,但我不能指出哪里因为它太复杂了!相反,我将解释为什么无法使用示例正确定义它。考虑:
Rand (\g -> (42,g)) >>= const mzero
我们需要取消42
,因此我们需要g
。获取g的地方来自绑定的返回值,所以答案肯定是:
Rand (\g -> ...)
对于某些...
,负责返回(b,g)
对。现在我们有42个,我们可以评估const mzero 42
并发现我们有RandZero
但是我们将在哪里获得b
?它无处可去(事实上,所以在这个例子中没有任何地方它可以是任何类型,因为表达式的类型是forall b. Rand b
)。
你的monad RandZero
的目的是什么?你只是想做StateT g Maybe
吗?我的猜测是你。在这种情况下,您可能有更多的运气试图实现此类型:
newtype Rand g a = Rand (g -> Maybe (a, g))
答案 1 :(得分:1)
如果我理解你的“monad”,(>>=)
就无法联想到。尝试定义
y' = do a <- do a' <- x
guard (a' /= 2)
return a'
guard (a /= 1)
return a
检查是否是这种情况。实际上,您的回溯策略只能撤消最后一步,而不是整个计算。