【发布时间】:2020-08-22 01:31:19
【问题描述】:
为什么需要在 Haskell 中为类型类规则显式编写检查(可能使用快速检查)?
例如用于测试 String monoid 的关联性:
leftIdcheck :: Monoid a => a -> Bool
leftIdcheck a = a <> mempty == a
quickCheck (leftIdcheck :: String -> Bool)
但是这工作量太大了!为什么 haskell 编译器不能自己默认检查所有这些并告诉我我的类型上的 monoid 实例不满足恒等律?
是否有任何库或语言扩展允许我们在编写程序时内置这些检查,而不必单独编写它们?这似乎很容易出错。
在相关的说明中,Agda 是让我们免费获得这些检查/证明,还是我们也必须在那里手动编写它们?
【问题讨论】:
-
因为通常无法验证这一点。这是赖斯定理的结果。
-
QuickCheck 尝试通过一些随机值来查找错误。它不会尝试所有这些,因为通常有无限多的值。可计算性理论确实证明了对语义属性(例如法律)的完美自动验证是不可能的。然而,Haskell 可以做的是为所有类和法则提供 QuickCheck 属性,以便于测试。我不知道有任何图书馆提供此功能,但原则上可以编写。
-
好的,不可能有一个算法肯定成功地证明“一般”所需的属性。但是,是否不可能提供一种允许失败但在某些简单情况下成功的算法?就像,编译器应该能够在简单的情况下派生
Eq类的实例,因此编译器显然可以说服自己相信x == x和/或x==y && y==z ⇒ x==z等属性。这节省了很多样板代码。当然,对于newtype NTei = NTei (Int -> Int) deriving Eq之类的东西如果失败也完全没问题。 -
@jpmarinier 在派生
Eq实例时,编译器不会对x==x之类的东西进行任何“思考”。它只是有一些关于A和B类型的相等性如何暗示(A,B)和Either A B上的相等性的硬编码规则,并且可以归纳地扩展到任何代数数据类型上的相等性。 -
@chi,有 Andrew Martin 的
quickcheck-classes和更早的checkers和genvalidity-hspec。我不知道它们之间的权衡,除了 Martin 的可能更容易使用。