2013-02-05 28 views
8

我在球拍/列表中定義了一個功能true?,與count一起使用。對球拍合同感到困惑

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

我發現我可以提供它的數值參數和我的功能會愉快地返回#f

> (true? 6) 
#f 

所以,我想我會探討使用球拍合約使非布爾參數返回合同違規中的錯誤。所以我把這個代碼在我的文件TOPE:

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

然而,增加的合同我仍然得到同樣的行爲,如上面的球拍REPL後。我不明白這是怎麼回事。我錯過了什麼?

+2

請注意,對於您的特定環境,您可能會使用'values',因爲除了'#f'之外,Racket會將所有內容視爲true。例如:'(count values'(多少#f true #f #f things #f))' – dyoo

回答

20

合同通常在模塊之間強制執行。所以你必須從外部角度來嘗試。但是,REPL適用於您正在使用的模塊內部。

從外部測試的簡單方法是使用test submodule。例如:

#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)))) 

更改合同和DrRacket重新運行,你應該看到你的合同生效這裏,因爲這裏的test模塊被視爲對合同的外部客戶。


另外,再拍文件require S上的第一次,然後就可以看到合同的效果也有。如果第一個文件被稱爲true-test.rkt,那麼你可以讓另一個模塊,然後:

#lang racket 
(require "true-test.rkt") 
(true? 42) ;; And _this_ should also raise a contract error. 
13

丹尼柳給了一個很好的答案。我只想對其進行擴展,並指出球拍確實爲您的合同執行地點提供了更大的靈活性(即,將合同邊界放在哪裏)。例如,你可以使用define/contract形式:

-> (define/contract (true? expr) 
    (-> boolean? boolean?) 
    (and (boolean? expr) expr #t)) 

將建立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] 

我發現define/contract特別有用的,如果我想測試的東西與REPL合同有關,在那裏我並不總是有一個模塊。但contract-out是默認建議,因爲在模塊邊界檢查合同通常是一個不錯的選擇。