简单的 QuickCheck 测试永远无法完成

Simple QuickCheck Test Never Completes

我在思考 QuickCheck 时遇到了一些麻烦。考虑以下简单数据类型及其对应的任意实例。

编辑:下面是评论中要求的完整代码。 fixedToFractionalMicro 等固定数值类型转换为 Fractional.

import Data.Fixed
import System.Random
import Control.Applicative
import Test.QuickCheck

fixedToFractional :: (HasResolution a, Fractional b) => Data.Fixed.Fixed a -> b
fixedToFractional = fromRational . toRational

instance Random Micro where
    randomR (lo, hi) g = randomR (fixedToFractional lo, fixedToFractional hi) g
    random g           = randomR (-999999, 999999) g

data FooType = FooType { foo :: Micro } deriving (Show)

instance Arbitrary FooType where
    arbitrary =
        FooType <$> x
        where
            x = choose (0.0, 1.0)

如果我理解正确,这应该允许生成随机 FooType 值,foo 字段设置为 0 到 1 之间的随机值。

接下来,考虑以下简单测试。

prop_foo_is_gte_zero ft = (foo ft) >= 0.0

当我尝试 运行 上述测试时,无论是在 ghci 中,还是在使用 quickCheckAll 的测试文件中,测试都无法完成。 ghc 在几秒钟内吃掉几 GB 的 RAM,如果我不杀掉它,最终 运行 我的机器将无法交换 space。我可能错过了一些令人难以置信的东西 fundamental/stupid,但(显然)不知道是什么。有什么想法吗?

编辑:我现在质疑我的 Random 实例。也许问题就在那里,而不是我的 Arbitrary 实例。

Micro

Random 实例似乎有问题

这里有一个快速的修复方法:

{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}

import Data.Fixed
import System.Random
import Test.QuickCheck

toDouble :: Micro -> Double
toDouble = realToFrac . toRational

instance Random Micro where
    randomR (lo, hi) g =
      let (a,g') = randomR (toDouble lo, toDouble hi) g
      in (fromRational (toRational a), g')
    random = randomR (-999999, 999999)

data FooType = FooType { foo :: Micro } deriving (Show)

instance Arbitrary FooType where
    arbitrary =
        FooType <$> x
        where
            x = choose (0.0, 1.0)

main :: IO ()
main = quickCheck prop_foo_is_gte_zero
  where prop_foo_is_gte_zero ft = foo ft >= 0.0