对球拍合同感到困惑

wdk*_*nls 9 racket

我定义了一个true?与球拍/列表中的计数一起使用的函数.

(define (true? expr)
  (and (boolean? expr) expr #t))
Run Code Online (Sandbox Code Playgroud)

我注意到我可以提供数字参数,我的功能很乐意返回#f.

> (true? 6)
#f
Run Code Online (Sandbox Code Playgroud)

所以,我想我会探索使用球拍合约来使非布尔参数在合同违规中返回错误.所以我把这个代码放在我的文件的顶部:

(provide (contract-out
          [true?         (-> boolean? boolean?)]))
Run Code Online (Sandbox Code Playgroud)

但是,在添加合同后,我仍然在球拍REPL中获得与上述相同的行为.我不明白这是怎么回事.我错过了什么?

dyo*_*yoo 21

合同通常模块之间强制执行.所以你必须从外部角度尝试它.但是,REPL适用于您正在使用的模块内部.

从外部测试的一种简单方法是使用测试子模块.例如:

#lang racket

(define (true? expr)
  (and (boolean? expr) expr #t))

(provide (contract-out
          [true?         (-> boolean? boolean?)]))   

(module* test racket/base
  (require (submod "..")
           rackunit)
  (check-true (true? #t))
  (check-false (true? #f))
  (check-exn exn:fail:contract? (lambda () (true? 3))))
Run Code Online (Sandbox Code Playgroud)

更改合同并在DrRacket中重新运行,您应该在此处看到您的合同生效,因为test此处的模块被视为合同的外部客户.


或者,制作另一个require第一个文件,然后你也可以看到合同的效果.如果调用了第一个文件true-test.rkt,那么您可以创建另一个模块,然后:

 #lang racket
 (require "true-test.rkt")
 (true? 42)  ;; And _this_ should also raise a contract error.
Run Code Online (Sandbox Code Playgroud)


Asu*_*awa 14

Danny Yoo给出了一个很好的答案.我只想扩展它,并注意到Racket确实为您提供了更强的合同执行地点(即合同边界的位置).例如,您可以使用以下define/contract表单:

-> (define/contract (true? expr)
     (-> boolean? boolean?)
     (and (boolean? expr) expr #t))
Run Code Online (Sandbox Code Playgroud)

这将在定义true?和所有其他代码之间建立合同检查:

-> (true? "foo")
; true?: contract violation
;  expected: boolean?
;  given: "foo"
;  in: the 1st argument of
;       (-> boolean? boolean?)
;  contract from: (function true?)
;  blaming: top-level
;  at: readline-input:1.18
; [,bt for context]
Run Code Online (Sandbox Code Playgroud)

define/contract如果我想在REPL上测试与合同相关的东西,我觉得特别有用,我并不总是有一个模块.但是,这contract-out是默认建议,因为在模块边界检查合同通常是一个不错的选择.