如何覆盖包代码提供的Haskell类型类实例?

Dav*_*ner 11 haskell quickcheck

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

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

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

上面的代码在编译时导致重复的实例声明错误.我可以使用默认生成器来获取此代码,但我想知道解决此问题的正确方法.

我考虑(但未测试)的一种可能的解决方案是Word8使用别名newtype.这将导致整个来源的许多变化,所以我希望有一个更清洁的方式.

编辑:如下面的评论所述,接受的答案非常简洁,易于实施:

newtype EncodedByte = EncodedByte Word8

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

Tho*_*son 10

一个newtype别名是标准的解决方案在这里.在大多数情况下,可能不包括你的,这不是什么大问题,因为newtype包装器只需要出现在你使用任意类型类的地方.例如,您可能处于某个顶级级别:

x <- arbitrary
Run Code Online (Sandbox Code Playgroud)

相反,你有

newtype SomeNewType = SNT Word8
instance Arbitrary SomeNewType where ...
....
    SNT x <- arbitrary
Run Code Online (Sandbox Code Playgroud)

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

import Test.QuickCheck hiding (Arbitrary(Word8))
Run Code Online (Sandbox Code Playgroud)

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

import Test.QuickCheck (quickCheck) -- note the implicit import of Arbitrary(..)
Run Code Online (Sandbox Code Playgroud)

  • 很多人似乎认为这个解决方案很难看.但是如果你允许"数据类型"的意思不仅仅是值的表示,我发现它是完全合理的.例如,你不只是在谈论`Word8`s,你在谈论`ControlCode或类似的东西. (5认同)