15

我有一些包含 QuickCheck 测试用例的旧 Haskell 代码。较新版本的 QuickCheck(我刚刚升级到 2.4.0.1)包括类型类实例 forArbitrary Word8和其他。这些在旧的 2.0.x 版本的 Test.QuickCheck.Arbitrary 中不存在。

虽然在一般意义上很有用,但包提供的Arbitrary Word8生成器并不是我想用于我的测试套件的那个:

instance Arbitrary Word8 where
  arbitrary = frequency [(2, oneof [return ctrlFrameDelim, return ctrlEscape, return ctrlXon, return ctrlXoff]),
                         (8, choose (0, 255))]

上面的代码在编译时会导致重复的实例声明错误。我可以取出这段代码并使用默认生成器,但我想知道解决这个问题的正确方法。

我考虑过(但未经测试)的一种可能的解决方案是Word8使用newtype. 这会导致整个源代码发生许多变化,所以我希望有一种更清洁的方法。

编辑:正如下面的评论中提到的,接受的答案非常干净且易于实施:

newtype EncodedByte = EncodedByte Word8

instance Arbitrary EncodedByte where
  arbitrary = liftM EncodedByte $ frequency [(2, elements [ctrlFrameDelim, ctrlEscape, ctrlXon, ctrlXoff]),
                                             (8, choose (0, 255))]
4

1 回答 1

13

newtype别名是这里的标准解决方案。在大多数情况下(可能不包括您的情况),这没什么大不了的,因为 newtype 包装器只需要出现在您使用 Arbitrary 类型类的地方。例如,您可能在某个顶层拥有:

x <- arbitrary

相反,你会有

newtype SomeNewType = SNT Word8
instance Arbitrary SomeNewType where ...
....
    SNT x <- arbitrary

您可能想要的不作为 GHC 扩展存在 - 您需要显式导入和导出实例。如果您有明确的实例导入,这将允许:

import Test.QuickCheck hiding (Arbitrary(Word8))

但是通过隐式导入实例破坏了许多当前工作的代码:

import Test.QuickCheck (quickCheck) -- note the implicit import of Arbitrary(..)
于 2011-04-13T01:20:38.380 回答