Racket 球拍合同依赖性评估两次?
输出是Racket 球拍合同依赖性评估两次?,racket,contract,Racket,Contract,输出是 #lang racket (module inside racket (provide (contract-out [dummy (->i ([x (lambda (x) (begin (displayln 0) #t))] [y (x) (lambda (y) (begin (displayln 1) #t))] [z (x y) (lambda (z) (beg
#lang racket
(module inside racket
(provide
(contract-out
[dummy (->i ([x (lambda (x) (begin (displayln 0) #t))]
[y (x) (lambda (y) (begin (displayln 1) #t))]
[z (x y) (lambda (z) (begin (displayln 2) #t))]
)
any
)]
)
)
(define (dummy x y z) #t)
)
(require 'inside)
(dummy 1 2 3)
我不清楚为什么将x
和y
作为依赖项会要求相应的守卫再次开火
->i
的文档似乎没有提到这种行为
任何人都可以解释一下这一点吗?这对我来说就像对你一样让人困惑,所以我抓住了这个机会。下面是对我的发现的总结
->i
combinator生成一个依赖契约,该契约使用本文中介绍的indy-burn语义。本文提出的关键思想是,对于从属合同,实际上可能有三方因违反合同而受到指责
对于正常功能合同,有两个潜在的犯罪方。第一个是最明显的一个,即调用方。例如:
>(定义/合同(foo x)
(整数?->.string?)
(数字->字符串x))
>(福“你好”)
foo:违反合同
期望值:整数?
给:“你好”
in:的第一个参数
(->整数?字符串?)
合同来自:(职能部门foo)
责备:匿名模块
(假设合同是正确的)
第二个潜在犯罪方是功能本身;也就是说,实现可能与合同不匹配:
>(定义/合同(条形图x)
(整数?->.string?)
十)
>(第1栏)
酒吧:违反了自己的合同
承诺:字符串?
制作:1
在:范围
(->整数?字符串?)
合同来源:(功能栏)
责备:(功能条)
(假设合同是正确的)
这两种情况都很明显。然而,->i
合同引入了第三个潜在的犯罪方:合同本身
由于->i
契约可以在契约附件时执行任意表达式,因此它们可能会违反自身。考虑以下合同:
(>i([mk-ctc(整数?->.contract?))
[val(mk ctc)(mk ctc“你好”)]
[结果编号/c])
这是一份有点愚蠢的合同,但很容易看出这是一份顽皮的合同。它承诺只使用整数调用mk-ctc
,但依赖表达式(mk-ctc“hello”)
使用字符串调用它!责备调用函数显然是错误的,因为它无法控制无效的契约,但是责备契约函数也可能是错误的,因为契约可以完全独立于它所附加的函数来定义
为了说明这一点,考虑一个多模块的例子:
#朗球拍
(模块m1)球拍
(提供反恐委员会)
(定义反恐委员会)
(->i([f(整数?->.integer?)]
[v(f)(λ(v)(>(f v)0))]
[结果(如有/c]))
(模块m2)球拍
(需要(子模块“.”m1))
(提供(外包[foo ctc]))
(定义(foo f v)
(f#f))
(需要平方米)
在本例中,ctc
契约在m1
子模块中定义,但使用契约的函数在单独的子模块m2
中定义。这里有两种可能的责任情景:
foo
函数显然无效,因为它将f
应用于#f
,尽管契约为该参数指定了(integer?->.integer?
)。您可以通过调用foo
在实践中看到这一点:
0
0
1
1
2
#t
合同错误的顶部是相同的(Racket为这类违反合同的行为提供相同的“违反自己的合同”消息),但责任信息是不同的!现在它将责任归咎于m1,这是合同的实际来源。这是印第谴责党->i
combinator目前没有实现任何此类优化,因为它可能不会对性能产生重大影响,而且契约的实现已经相当复杂(尽管如果有人想要实现它,它可能会被接受)
但是,一般来说,契约应该是无状态且幂等的(平面契约应该是简单的谓词),因此不能保证不会发生这种情况,->i
只是使用它来实现其细粒度的信息
一,。事实证明,
->d
合同组合器根本没有抓住这个问题,因此add1
最终在这里引发了合同违约。这就是为什么创建了->i
,这也是为什么->i
比->d
更受青睐的原因
> (foo add1 0)
foo: broke its own contract
promised: integer?
produced: #f
in: the 1st argument of
the f argument of
(->i
((f (-> integer? integer?))
(v (f) (λ (v) (> (f v) 0))))
(result any/c))
contract from: (anonymous-module m2)
blaming: (anonymous-module m2)
(assuming the contract is correct)
> (foo add1 "hello")
foo: broke its own contract
promised: integer?
produced: "hello"
in: the 1st argument of
the f argument of
(->i
((f (-> integer? integer?))
(v (f) (λ (v) (> (f v) 0))))
(result any/c))
contract from: (anonymous-module m1)
blaming: (anonymous-module m1)
(assuming the contract is correct)