【问题标题】:How do you override Haskell type class instances provided by package code?你如何覆盖包代码提供的 Haskell 类型的类实例?
【发布时间】:2011-04-13 01:10:29
【问题描述】:

我有一些包含 QuickCheck 测试用例的旧 Haskell 代码。较新版本的 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 起别名。这会导致整个源代码发生许多变化,所以我希望有一种更清洁的方法。

编辑:正如下面的 cmets 所述,接受的答案非常干净且易于实施:

newtype EncodedByte = EncodedByte Word8

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

【问题讨论】:

    标签: haskell quickcheck


    【解决方案1】:

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

    【讨论】:

    • 很多人似乎认为这个解决方案丑陋。但是,如果您允许“数据类型”的含义不仅仅是值的表示,我认为这是完全合理的。例如,您不仅在谈论 Word8s,还在谈论 ControlCodes 或类似的东西。
    • 效果很好。事实证明,别名不需要任何级联更改。我只需要为“选择”提供一个额外的“实例随机 SomeNewType”声明。
    猜你喜欢
    • 2019-10-04
    • 2020-01-25
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多