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

有无可自动匹配类型约束生成测试用例的Haskell测试套件?

寻找支持多态函数通用测试的Haskell工具

问题背景

我在学习Haskell时重写了不少标准库函数,代码能通过类型检查,但不确定行为是否完全符合原函数。比如我实现了自己的liftA2:

-- 自定义liftA2实现
liftA2' :: Applicative app => (a -> b -> c) -> app a -> app b -> app c
liftA2' f aa ab = f <$> aa <*> ab

我想验证它在任意函数f和任意Applicative实例下都和标准liftA2表现一致,但用QuickCheck的话必须指定具体的函数和类型实例,比如:

-- 仅针对(,)函数和[Int]实例的测试
quickCheck $ \aa bb -> liftA2 (,) aa bb === liftA2' (,) (aa :: [Int]) (bb :: [Int])

这种方式不仅写法繁琐,还只能覆盖特定场景,无法做到通用验证。我希望能写出类似check $ liftA2 === liftA2'的代码,让测试工具自动生成符合类型约束的多种测试用例,覆盖边界情况并报告覆盖率。

可用工具与方案

1. QuickCheck + polycheck

polycheck是QuickCheck的扩展,专门解决多态函数的通用测试问题。它借助GHC的类型系统自动推导多态类型的各种实例,无需手动指定具体类型或函数。用法极简:

import Test.QuickCheck.Poly

check $ liftA2 === liftA2'

它会自动挑选多种常用Applicative实例(如[]、Maybe、Either e)和不同类型的函数f生成测试用例,覆盖通用场景。

2. Hedgehog

Hedgehog是比QuickCheck更灵活的属性测试库,原生支持简洁的多态测试写法。虽然需要编写少量生成器代码,但它的多态生成器能自动适配不同类型,轻松扩展到各类Applicative实例:

import Hedgehog
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range

prop_liftA2_equiv :: Property
prop_liftA2_equiv = property $ do
  f <- forAll $ Gen.fun (Gen.int Range.linearBounded)
  aa <- forAll $ Gen.list (Range.linear 0 10) Gen.int
  bb <- forAll $ Gen.list (Range.linear 0 10) Gen.int
  liftA2 f aa bb === liftA2' f aa bb

若要测试Maybe这类其他实例,只需把Gen.list换成Gen.maybe即可,无需大幅修改测试代码。

3. inspection-testing(编译时语义验证)

如果想直接证明两个函数语义完全等价,而非依赖测试用例抽样验证,可以使用inspection-testing这个GHC插件。它在编译阶段检查两个函数的核心中间表示是否一致,适合像liftA2'这种由标准组合子直接构成的实现:

{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
import Test.Inspection

inspect $ 'liftA2 === 'liftA2'

若两个函数实现逻辑存在差异,编译时会直接报错,无需等到运行测试,效率更高。

总结

  • 追求运行时自动生成多态测试用例:优先用polycheck(基于QuickCheck)或Hedgehog;
  • 需要编译时严格验证语义等价:选择inspection-testing;
  • 这些工具都能帮你摆脱手动指定类型和函数的繁琐,实现接近check $ f === f'的极简测试写法。

内容的提问来源于stack exchange,提问作者Blue Nebula

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 10:50:26