2013-02-05 27 views
8

Ich definierte eine Funktion true? für die Verwendung mit count in Schläger/Liste.Verwirrt über Racket Verträge

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

Ich bemerkte ich es numerische Argumente und meine Funktion glücklich #f zurückkehren würde bieten könnte.

> (true? 6) 
#f 

Also, ich dachte, ich würde erkundet einen Schläger Vertrag mit nicht-boolean Argumenten einen Fehler in Vertragsverletzung zu machen. Also habe ich diesen Code auf dem Tope meiner Datei:

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

jedoch nach Vertrag Zugabe ich immer noch das gleiche Verhalten wie oben im Schläger REPL. Ich verstehe nicht, wie das sein könnte. Was vermisse ich?

+2

Beachten Sie, dass Sie in Ihrem speziellen Kontext "Werte" verwenden können, da Racket alles außer "# f" als wahr behandelt. Zum Beispiel: '(Zählwerte '(wie viele #f wahre #f # f Dinge #f))' – dyoo

Antwort

20

Verträge werden normalerweise zwischen Module erzwungen. Sie müssten es also von außen versuchen. Die REPL bezieht sich jedoch auf das Innere des Moduls, in dem Sie arbeiten.

Eine einfache Möglichkeit, von außen zu testen, ist die Verwendung eines test submodule. Zum Beispiel:

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

die Verträge ändern und starten in DrRacket, und Sie sollten Ihre Verträge in der Tat hier, da das test Modul hier sehen, ist als externer Kunde des Vertrages behandelt werden.


Alternativ machen eine andere Datei, dass require s das erste, und dann können Sie die Wirkung der Verträge dort zu sehen. Wenn die erste Datei true-test.rkt aufgerufen wird, dann können Sie ein anderes Modul machen, und dann:

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

Danny Yoo gab eine ausgezeichnete Antwort. Ich wollte nur darauf eingehen und feststellen, dass Racket Ihnen mehr Flexibilität gibt, wo Ihr Vertrag durchgesetzt wird (d. H. Wo die Vertragsgrenze gesetzt werden soll). Zum Beispiel können Sie die define/contract Formular:

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

die Vertragsprüfung zwischen der Definition von true? und allen anderen Code etablieren:

-> (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] 

Ich finde define/contract besonders nützlich, wenn ich etwas will testen im Zusammenhang mit Verträgen an der REPL, wo ich nicht immer ein Modul habe. contract-out ist jedoch die Standardempfehlung, da das Überprüfen von Verträgen an Modulgrenzen normalerweise eine gute Wahl ist.