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

发布于 2024-11-01 02:21:23 字数 954 浏览 1 评论 0原文

我有一些旧的 Haskell 代码,其中包括 QuickCheck 测试用例。较新版本的 QuickCheck(我刚刚升级到 2.4.0.1)包括 Arbitrary 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))]

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

我考虑过(但未测试)的一种可能的解决方案是使用 newtypeWord8 提供别名。这会导致整个源代码发生许多变化,所以我希望有一种更干净的方法。

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

newtype EncodedByte = EncodedByte Word8

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

I have some old Haskell code that includes QuickCheck test cases. Newer versions of QuickCheck (I've just upgraded to 2.4.0.1) include type class instances for Arbitrary Word8 and others. These did not exist in older 2.0.x versions of Test.QuickCheck.Arbitrary.

While useful in the general sense, the package-provided Arbitrary Word8 generator is not the one I want to use for my test suite:

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

The above code causes a duplicate instance declaration error at compile-time. I can take this code out and get by with the default generator but I'd like to know the proper way to solve this.

One possible solution I've considered (but not tested) is aliasing Word8 using newtype. That would cause many changes throughout the source so I'm hoping there is a cleaner way.

EDIT: As mentioned in the comments below, the accepted answer was very clean and easy to implement:

newtype EncodedByte = EncodedByte Word8

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

野稚 2024-11-08 02:21:23

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(..)

A newtype alias is the standards solution here. In most cases, which might not include yours, this isn't a big deal because the newtype wrapper only needs to appear where you use the Arbitrary typeclass. For example, you might have at some top level:

x <- arbitrary

And instead you'd have

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

What you probably want doesn't exist as a GHC extension - you want explicit importing and exporting of instances. If you had explicit instance imports this would allow:

import Test.QuickCheck hiding (Arbitrary(Word8))

But break lots of code that currently works by implicit imports of instances:

import Test.QuickCheck (quickCheck) -- note the implicit import of Arbitrary(..)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文