将契约设计与类型系统进行比较
我最近读了一篇论文,将合同设计与测试驱动开发进行了比较。 DbC 和 TDD 之间似乎有很多重叠、一些冗余以及一些协同作用。例如,有基于合同自动生成测试的系统。
DbC 以什么方式与现代类型系统重叠(例如在 haskell 中,或其中一种依赖类型的语言),并且使用两者是否比其中任何一个更好?
I recently read a paper that compared Design-by-Contract to Test-Driven-Development. There seems to be lot of overlap, some redundancy, and a little bit of synergy between the DbC and TDD. For example, there are systems for automatically generating tests based on contracts.
In what way does DbC overlap with modern type system (such as in haskell, or one of those dependently typed languages) and are there points where using both is better than either?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
Ralf Hinze 的论文函数式编程的类型化合约, Johan Jeuring 和 Andres Löh 制作了这张方便的表格,说明了合同在“检查”设计范围中的位置:
The paper Typed Contracts for Functional Programming by Ralf Hinze, Johan Jeuring, and Andres Löh had this handy table that illustrates whereabouts contracts sit in the design spectrum of "checking":
似乎大多数答案都假设合约是动态检查的。
请注意,在某些系统中,合约是静态检查的。在
在此类系统中,您可以将合同视为一种受限制的形式
可以自动检查的依赖类型。对比一下这个
具有更丰富的依赖类型,可以交互检查,例如
在柯克。
请参阅 Dana Xu 页面 上的“规格检查”部分,了解
关于静态和混合检查(静态后动态)的论文
Haskell 和 OCaml 的合同。徐氏的契约制度包括
细化类型和依赖箭头,两者都是依赖的
类型。具有受限依赖类型的早期语言是
自动检查包括 DML 和 ATS。
在 DML 中,与 Xu 的工作不同,依赖类型受到限制,因此
自动检查完成。
It seems most answers assume that contracts are checked dynamically.
Note that in some systems contracts are checked statically. In
such systems you can think of contracts as a restricted form of
dependent types which can be checked automatically. Contrast this
with richer dependent types, which are checked interactively, such as
in Coq.
See the "Specification Checking" section on Dana Xu's page for
papers on static and hybrid checking (static followed by dynamic) of
contracts for Haskell and OCaml. The contract system of Xu includes
refinement types and dependent arrows, both of which are dependent
types. Early languages with restricted dependent types that are
automatically checked include the DML and ATS of Pfenning and Xi.
In DML, unlike in Xu's work, the dependent types are restricted so
that automatic checking is complete.
主要区别在于,测试是动态且不完整的,依赖于测量来证明您已经完全验证了您正在测试的任何属性,而类型和类型检查是一个正式的系统,可确保所有可能的代码路径都已针对您正在测试的任何属性进行了验证以类型说明。
对属性的测试只能达到同一属性的类型检查提供的开箱即用的保证级别的限制。合同增加了动态检查的基线。
The primary differences is that testing is dynamic and incomplete, relying on measurement to give evidence that you have fully validated whatever property you are testing, while types and typechecking is a formal system that guarantees all possible code paths have been validated against whatever property you are stating in types.
Testing for a property can only approach in the limit the level of assurance a type check for the same property provides out of the box. Contracts increase the base line for dynamic checking.
只要您无法表达类型系统本身的所有假设,DBC 就很有价值。简单的 haskell 示例:
类型为:
然而,对于 n 来说,只有大于等于 0 的值才可以。这是 DBC 可以介入的地方,例如,生成适当的快速检查属性。
(当然,在这种情况下,检查负值并修复除未定义之外的结果也太容易了 - 但还有更复杂的情况。)
DBC is valuable as long as you can't express all the assumptions in the type systen itself. Simple haskell example:
The type would be:
Yet, only values greater-equal 0 are ok for n. This is where DBC could step in and, for example, generate appropriate quickcheck properties.
(Of course, in this case, it is too easy to check also for negative values and fix an outcome other than undefined - but there are more complex cases.)
我认为DbC和type的系统没有可比性。 DbC 和类型系统(甚至验证系统)之间存在混淆。例如,我们可以找到比较DbC和Liquid Haskell工具或DbC和QuickCheck框架。恕我直言,这是不正确的:类型的系统以及形式证明系统只断言一个 - 你:你在我们的脑海中有一些算法,并且你声明了这些算法的属性。然后你实现这些算法。类型系统以及形式证明系统验证实现代码是否对应于声明的属性。
DbC 验证的不是内部事物(实现/代码/算法),而是外部事物:代码外部事物的预期功能。它可以是环境、文件系统、数据库、调用者的状态,当然还有你自己的状态,任何东西。典型的合约在运行时工作,而不是在编译时或特殊验证阶段。
DbC 的规范示例显示了如何在 HP 芯片中发现错误。发生这种情况是因为 DbC 声明了外部组件的属性:芯片的属性、其状态、转换等。如果您的应用程序遇到意外的外部世界状态,它会将这种情况报告为异常。这里的神奇之处在于:1)您在一个地方定义合约并且不要重复自己2)合约可以轻松关闭(从编译的二进制文件中删除)。恕我直言,它们更接近方面,因为它们不像子例程调用那样“线性”。
我在这里回顾一下,DbC 比类型系统更有助于避免现实世界的错误,因为大多数真正的错误是由于对外部世界/环境/框架/操作系统组件/等的行为的误解而发生的。类型和证明帮助仅有助于避免您自己的简单错误,这些错误可以通过测试或建模(在 MatLab、Mathematica 等中)发现。
简而言之:您无法在具有类型系统的 HP 芯片中找到错误。当然,存在一种幻觉,认为索引单子之类的东西是可能的,但具有这种尝试的真实代码将看起来超级复杂、不支持且不实用。但我认为可能存在一些混合方案。
I think DbC and type's systems are not comparable. There are confusion between DbC and type systems (or even verification systems). For example, we can find comparing DbC and Liquid Haskell tool or DbC and QuickCheck framework. IMHO it's not correct: type's systems as well as formal prove systems assert only one - you: you have some algorithms in our mind and you declare properties of these algorithms. Then you implement these algorithms. Types systems as well as formal prove systems verify that the code of implementation corresponds to the declared properties.
DbC verifies not internal things (implementation/code/algorithm) but external things: expected features of things which are external to your code. It can be state of the environment, of file system, of DB, callers, sure your own state, anything. Typical contracts work at runtime, not at compile time or in special verification phase.
Canonical example of DbC shows how was found bug in HP chip. It happens because DbC declares properties of external component: of the chip, its state, transitions, etc. And if your application hits unexpected external world state, it report such case as exception. Magic here is that: 1) you define contracts in one place and don't repeat yourself 2) contracts can be easy turned-off (dropped out from compiled binary). They are more close to Aspects IMHO, due they are not "linear" like subroutines calls.
My recap here is that DbC are more helpful to avoid real world bugs than types systems, because most real bugs happen due to misunderstanding of behavior of external world/environment/frameworks/OS components/etc. Types and prove assistance help only to avoid your own simple errors which can be found with tests or modeling (in MatLab, Mathematica, etc, etc).
In short: you can not find bug in HP chip with types system. Sure, exists illusion that it's possible to something like indexed monads, but real code with such attempts will look super complex, unsupportable and not practical. But I think there are possible some hybrid schemes.