【问题标题】:Very slow guards in my monadic random implementation (haskell)我的一元随机实现中非常慢的守卫(haskell)
【发布时间】:2010-04-01 06:21:39
【问题描述】:

我尝试编写一个基于数字类的随机数生成器实现。我还在那里添加了 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)。这是意料之外的,如果我删除一名守卫,它的工作速度非常快。为什么在这种情况下它运行得太慢了?

我做错了什么?

【问题讨论】:

  • 不相关:Haskell 中的标准随机数生成器 很慢。改用 System.Random.Mersenne。
  • 好的。但是,当我尝试 (System.Random) 时,为什么要使用这么多内存?我认为,>>=定义中的问题。是尾递归吗?我认为是。
  • 我还不知道——但你可以使用guard (a /= 1 &amp;&amp; a /= 2)
  • 当然。但是,当我的“做”声明中有许多警卫时,我就有动力使用警卫。

标签: performance haskell random monads


【解决方案1】:

您对(&gt;&gt;=) 的定义肯定是错误的,但我无法指出哪里,因为它太复杂了!相反,我将用一个例子来解释为什么它不能被正确定义。考虑:

Rand (\g -> (42,g)) >>= const mzero

我们需要把42 拿出来,所以我们需要g。得到g的地方是从bind的返回值来的,所以答案肯定是:

Rand (\g -> ...)

对于一些...,负责返回一个(b,g) 对。现在我们有 42 个,我们可以评估 const mzero 42 并发现我们有 RandZero 但是我们从哪里得到 b?它无处不在(事实上,所以在这个例子中没有任何地方可以是任何类型,因为表达式的类型是forall b. Rand b)。

RandZero 对你的 monad 有什么作用?你只是想制作StateT g Maybe吗?我的猜测是你是。在这种情况下,您可能会更幸运地尝试实现 this 类型:

newtype Rand g a = Rand (g -> Maybe (a, g))

【讨论】:

    【解决方案2】:

    如果我正确理解了您的“monad”,(&gt;&gt;=) 将无法关联。尝试定义

    y' = do a <- do a' <- x
                    guard (a' /= 2)
                    return a'
            guard (a /= 1)
            return a
    

    检查是否是这种情况。实际上,您的回溯策略只能撤消最后一步,而不是整个计算。

    【讨论】:

    • 我意识到我的策略是错误的,现在我正在使用 Liquid 的策略——它非常适合我的目的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-19
    • 1970-01-01
    • 2020-05-03
    • 2019-03-01
    • 1970-01-01
    • 2016-07-31
    • 2015-07-27
    相关资源
    最近更新 更多