0

对于使用 QuickCheck,我正在尝试实现 Arbitrary 实例:

import Test.QuickCheck
import Test.QuickCheck.Arbitrary (class Arbitrary, class Coarbitrary)

data Arith = Lit Int | Add Arith Arith | Neg Arith

derive instance arithEq :: Eq Arith

instance arbitraryFoo :: Arbitrary Arith where
    arbitrary = arbLit <|> arbAdd <|> arbNeg where
        arbAdd = do
            a <- arbitrary
            b <- arbitrary
            pure $ Add a b
        arbNeg = do
            a <- arbitrary
            pure $ Neg a
        arbLit = do
            x <- arbitrary
            pure $ Lit x

但是 PureScript 告诉我

The value of arbitraryFoo is undefined here, so this reference is not allowed.

当我从错误消息中更改我的代码到指南时:

import Test.QuickCheck
import Test.QuickCheck.Arbitrary (class Arbitrary, class Coarbitrary)
import Control.Lazy

instance arbitraryFoo :: Arbitrary Arith where
    arbitrary = fix $ \arb -> let
        arbAdd = do
            a <- arb
            b <- arb
            pure $ Add a b
        arbNeg = do
            a <- arb
            pure $ Neg a
        arbLit = do
            x <- arbitrary
            pure $ Lit x
        in arbLit <|> arbAdd <|> arbNeg

我仍然有一些错误:

RangeError: Maximum call stack size exceeded

那么,我该如何解决呢?为什么Arbitrary不能自动导出?

4

1 回答 1

0

为了防止它生成无限递归结构,您应该制作生成器sized,然后每次递归使用它resize-1

这是使用该技术的 JSON 生成器的示例:https ://github.com/purescript-contrib/purescript-argonaut-core/blob/37fc57c722851b1936c438db750aa8195dc630c7/src/Data/Argonaut/Gen.purs 。尽管Gen是用 抽象的MonadGen,但如果您想实现 ,同样的原则也适用Arbitrary

于 2018-07-07T20:41:20.870 回答