我偶尔会看到有人说QuickCheck中的Gen类型不遵守monad法则,尽管我没有看到很多解释。现在,QuickCheck 2.7的Test.QuickCheck.Gen.Unsafe模块说Gen只是“道德上”的monad,但简短的解释让我摸不着头脑。你能否一步一步地说明Gen如何打破monad法律?
答案 0 :(得分:25)
如果你想证明某些东西是单子,那么你必须证明它符合monad法则。这是一个
m >>= return = m
Gen
的文档指的是该法律中(=)
的实际含义。 Gen
值是函数,因此很难比较它们的相等性。相反,我们可能会内联(>>=)
和return
的定义,并通过等式推理证明法律适用
m = m >>= return
m = m >>= (\a -> MkGen (\_ _ -> a))
MkGen m = MkGen m >>= (\a -> MkGen (\_ _ -> a))
MkGen m = MkGen (\r n ->
let (r1,r2) = split r
MkGen m' = (\a -> MkGen (\_ _ -> a)) (m r1 n)
in m' r2 n
)
MkGen m = MkGen (\r n ->
let (r1,r2) = split r
MkGen m' = MkGen (\_ _ -> m r1 n)
in m' r2 n
)
MkGen m = MkGen (\r n ->
let (r1,r2) = split r
in (\_ _ -> m r1 n) r2 n
)
MkGen m = MkGen (\r n ->
let (r1,r2) = split r
in m r1 n
)
MkGen m = MkGen (\r -> m (fst $ split r))
所以,最终,除非fst . split == id
,which is doesn't,否则monad法律似乎无法成立。不应该。
但从道德上讲,fst (split r)
与r
相同吗?好吧,只要我们操作好像我们对种子价值一无所知,是的,fst . split
在道德上等同于id
。 Gen
- as-a-function产生的实际值会有所不同,但值的分布是不变的。
这就是文档所指的内容。我们在monad法则中的平等并不等同,而是通过将Gen a
视为a
的值的概率分布而仅在“道德上”。