RacketScheme的“合同设计”是如何实现的?与埃菲尔铁塔有何不同?
我知道Eiffel(其鼻祖)和Racket都实现了“Design by Contract”的功能。可悲的是,我不确定其中一个与另一个有何不同。 Eiffel 的 DBC 依赖于 OOP 范式和继承,但 Racket 这种截然不同的语言如何解释这种差异呢?
I know that both Eiffel (the progenitor) and Racket both to implement "Design by Contract" features. Sadly, I am not sure how one would different from the other. Eiffel's DBC is reliant on the OOP paradigm and inheritance, but how would Racket, a very different language account for such a disparity?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Racket 因合同而闻名的主要特点是责备的概念,而处理 ho 函数无疑是日常 Racket 编程的重要组成部分。
您可能还想查看本文的前两部分:
http: //www.ccs.neu.edu/scheme/pubs/oopsla01-ff.pdf
Racket's main claim to contract fame is the notion of blame, and dealing with ho function is a big part of that for everyday Racket programming, definitely.
You might also want to check out the first two sections of this paper:
http://www.ccs.neu.edu/scheme/pubs/oopsla01-ff.pdf
首先,此时您最好的信息来源是球拍指南,其目的是作为介绍性文本而不是参考手册。具体来说,有一个内容广泛的关于合约的章节会有所帮助。编辑:另请参阅罗比指出的论文,他是 Racket 的主要合同工。
至于你的问题——我对埃菲尔合同制度不太了解,但我认为它先于Racket的制度。然而(这又是一个“IIRC”)我认为 Racket 的合约系统是第一个引入更高阶合约的系统。具体来说,当您处理高阶函数时,分配适当的责备会变得更加复杂——例如,如果您采用具有
X? 契约的
并且您向其发送了一个与foo
函数。 -> Y?X?
不匹配的值,那么将该值发送给foo
的客户端代码就会受到指责。但如果你的函数是(X? -> Y?) -> Z?
和X?
谓词不满足,那么责任归咎于foo
本身,而不是客户端(如果Y?< /code> 不满意,那么责任仍然在客户身上)。
First of all, your best source of information at this point is the Racket Guide, which is intended as an introductory text rather than a reference manual. Specifically, there is an extensive chapter about contracts that would help. EDIT: Also see the paper that Robby pointed at, he's the main Racket contract guy.
As for your question -- I don't know much about the Eiffel contract system, but I think that it precedes Racket's system. However (and this is again an "IIRC") I think that Racket's contract system was the first one that introduced higher order contracts. Specifically, when you deal with higher order functions assigning proper blame gets a little more complicated -- for example, if you take a
foo
function that has a contract ofX? -> Y?
and you send it a value that doesn't matchX?
then the client code that sent this value tofoo
is blamed. But if your function is(X? -> Y?) -> Z?
and theX?
predicate is not satisfied, then the blame goes tofoo
itself, not to the client (and ifY?
is not satisfied then the blame is still with the client).我想你是在问,如果没有 OOP 和继承,契约系统如何工作?作为一个不熟悉 Eiffel 的 Racket 用户,我想知道为什么契约系统会与 OOP 和继承有关。 :)
在实践层面上,我认为 Racket 契约是一种获得静态类型声明的一些好处,同时保持动态类型语言的灵活性的方法。另外,合约不仅仅是类型,还可以充当断言的角色。
例如,我可以说一个函数需要一个精确整数的参数...但也可以说它应该是一个精确的正整数,或者某些特定值的并集,或者实际上是任意的通过值的复杂测试。通过这种方式,Racket 中的契约结合了您可以使用 C/C++ 中的 (a) 类型声明和 (b) 断言执行的操作。
Racket 中合约的一个问题是它们可能很慢。解决这个问题的一种方法是首先在开发时使用它们,然后有选择地删除它们,特别是从“内循环”类型的函数中。我尝试过的另一种方法是批量打开/关闭它们:制作一对模块,例如contracts-on.rkt和contract-off.rkt,后者提供了一些不执行任何操作的宏。让您的模块需要一个contracts.rkt,它提供来自-on 或-off 文件的所有内容。这就像在 DEBUG 与 RELEASE 模式下编译一样。
如果您来自 Eiffel,也许我对 Racket 合同的 C/C++ 倾向不会有帮助,但无论如何我想分享它。
I think you're asking, how could a contract system work without OOP and inheritance? As a user of Racket who is unfamiliar with Eiffel, I'm wondering why a contract system would have anything to do with OOP and inheritance. :)
On a practical level I think of Racket contracts as a way to get some of the benefits of static type declarations, while keeping the flexibility of dynamically typed languages. Plus contracts go beyond just types, and can fill the role of asserts.
For instance I can say a function requires one argument that is an exact integer ... but also say that it should be an exact positive integer, or a union of certain specific values, or in fact any arbitrarily complicated test of the passed value. In this way, contracts in Racket combine what you might do with both (a) type declarations and (b) assertions in say C/C++.
One gotcha with contracts in Racket is that they can be slow. One way to deal with this is to use them at first while developing, then remove them selectively especially from "inner-loop" types of functions. Another approach I've tried is to turn them on/off wholesale: Make a pair modules like contracts-on.rkt and contract-off.rkt, where the latter provides some do-nothing macros. Have your modules require a contracts.rkt, which provides all from either of the -on or -off files. This is like compiling in DEBUG vs RELEASE mode.
If you're coming from Eiffel maybe my C/C++ slant on Racket contracts won't be helpful, but I wanted to share it anyway.