You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell QuickCheck缺少Natural和Dyadic的Arbitrary实例如何解决?

问题原因和最优解决方案

  1. QuickCheck核心包不内置Natural的Arbitrary实例,这类非Prelude标准类型的实例都拆分在quickcheck-instances扩展包中,需要额外引入依赖并导入对应实例模块。
  2. 最符合Haskell开发习惯的方案是直接为自定义的Dyadic类型实现Arbitrary实例,一次性解决两类报错,后续写其他属性测试也更简洁。

操作步骤

步骤1:添加项目依赖

在你的项目cabal文件的build-depends字段中加入两个依赖:

build-depends:
  base >=4.14 && <5,
  QuickCheck >=2.14,
  quickcheck-instances >=0.3

如果用Stack管理项目,对应在stack.yaml的extra-deps中确认存在这两个包即可。

步骤2:导入必要模块

在测试文件头部补充导入两个模块:

-- 导入Arbitrary类型类
import Test.QuickCheck.Arbitrary
-- 导入Natural的Arbitrary实例,不需要导入具体函数所以写空导入
import Test.QuickCheck.Instances.Natural ()

步骤3:为Dyadic实现Arbitrary实例

可以直接在测试文件中写实例(不需要改Dyadic类型的定义模块,属于孤儿实例,测试场景下是完全可接受的):

instance Arbitrary Dyadic where
  -- 直接复用Integer和Natural的任意值生成逻辑构造Dyadic
  arbitrary = Dyadic <$> arbitrary <*> arbitrary
  -- 可选实现shrink方法:测试失败时自动收缩到最小复现用例,大幅提升调试效率
  shrink (Dyadic n p) = uncurry Dyadic <$> shrink (n, p)

步骤4:改回简洁的测试函数签名

你最开始写的Dyadic -> Dyadic -> Bool的签名是完全可用的,不需要拆成四个参数:

dyadic_add :: Dyadic -> Dyadic -> Bool
dyadic_add d1 d2 = 
  dyadic_to_rational (d1 `plus` d2) == dyadic_to_rational d1 + dyadic_to_rational d2

另外注意你的Dyadic类型定义需要派生Eq和Show,否则hspec无法判断测试结果、也无法打印失败的用例:

data Dyadic = Dyadic Integer Natural deriving (Eq, Show)

如果不想给Dyadic写Arbitrary实例,只想临时解决Natural的报错,只要完成步骤1和导入Test.QuickCheck.Instances.Natural ()即可,无需写自定义实例,但显然给Dyadic加实例的方案复用性更高、代码更简洁。


内容的提问来源于stack exchange,提问作者Alex Altair

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 16:57:06