如何在PureScript中快速检查自定义ADT?

时间:2018-07-06 17:15:45

标签: purescript quickcheck property-based-testing

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

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无法自动导出?

1 个答案:

答案 0 :(得分:0)

为防止其生成无限递归结构,您应使生成器sized,然后使resize-1,每次使其递归使用。

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