我在纸牌游戏中做了一些假设检验。
为此,我实施了游戏和玩游戏的AI。对于测试,我必须在我的牌组中所有可能的卡片安排的空间上进行抽样(牌组有24张牌,所以有24张不同的牌组初始状态)。然而,抽样应该是独立的,因为(a)在洗牌之后,每个初始安排应该具有概率(1/24!)和(b)如果i和i'在两次洗牌之后的两个初始安排是安排我和然后安排i'最初的安排应该是(1/24!)x(1/24!)。[注1]
所以,如果 d 是我的牌组,那么 shuffleDeck 就是我洗牌的功能。我相信随机monad的构建方式是概率((suffleDeck d)== i)= 1/24!
但我的问题是:当与函数replicateM交互时,此函数是否独立?换句话说,以下是真的吗?
P((replicateM 2(shuffleDeck d))== [i,i'])= P((suffleDeck d)== i)* P((suffleDeck d)== i&#39 ;)
其中P(x = X)是x为X的概率。
我用于shuffle的代码如下:
import System.Random
shuffleDeck d = do
seed <- newStdGen
return $ shuffle seed d
shuffle :: StdGen -> [Card] -> [Card]
shuffle g [] = []
shuffle g d = c : shuffle g' d'
where (c, g') = oneRandomCard g d
d' = d\\[c]
oneRandomCard :: StdGen -> [Card] -> (Card, StdGen)
oneRandomCard g d =((last $ take n d), g1 )
where (n,g1) = randomR (1, length d) g
我看到第一眼看来这个问题似乎微不足道,但考虑到haskell对待随机性的方式,我觉得值得提问。
[1]注意:分配不需要像我说的那样统一。它只需要是一个已知的分布,所以我可以掌握测试的力量。但在这种情况下它应该是统一的。
[2]注意:如注释中所述,该函数仅使用System.Random而不是Control.Monad.Random。
答案 0 :(得分:5)
由于您的示例仅使用replicateM
中的IO
,因此问题实际上略显不完整。 replicateM 2 (shuffleDeck d)
的类型为IO [[Card]]
。它永远不会等同[[Card]]
类型的东西。但是,虽然这个技术问题在使用Haskell时非常重要,但我会忽略它来回答我认为是你的基本问题。
据我所知,您的基本问题是以下两段代码之间是否存在差异:
decks d = replicateM 2 (shuffleDeck d)
和
decks d = do
d1 <- shuffleDeck d
d2 <- shuffleDeck d
return [d1, d2]
如果这两者之间存在差异,则会破坏相关类型的Monad
实例。 monad法则与replicateM
的定义相结合,要求这些表达式具有相同的结果。
答案 1 :(得分:2)
首先,很好的问题。并回答你的问题,是的,你的等式确实存在。在您的代码中,您显式线程化了生成器而不是使用MonadRandom。当你使用MonadRandom时,你应该会发现你的方程式不仅仅能保持,而且两种不同的双重混乱方法实际上应该会给你相同的改组。 (这假设您以确定的方式而不是使用IO为种子生成种子)。均等推理和反馈透明度是强大的。如果我能进一步澄清,请告诉我。