2013-02-05 16 views
8

Ho definito una funzione true? per l'uso con count in racket/list.Confuso per contratti di racket

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

ho notato che potrei fornire argomenti numerici e la mia funzione tornerei molto volentieri #f.

> (true? 6) 
#f 

Così, ho pensato di esplorare con un contratto racchetta per rendere gli argomenti non booleani restituiscono un errore in violazione del contratto. Così ho messo questo codice nella parte tope del mio file:

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

Tuttavia, dopo aver aggiunto il contratto ho ancora ottenere lo stesso comportamento sopra nella REPL racket. Non capisco come potrebbe essere. Cosa mi manca?

+2

Nota che per il tuo particolare contesto, potresti essere in grado di usare 'valori', poiché Racket considera tutto come vero eccetto per' # f'. Es .: '(valore di conteggio '(quante volte #f vero #f #f cose #f))' – dyoo

risposta

20

I contratti sono generalmente applicati tra i moduli. Quindi dovresti provarlo dalla prospettiva esterna. Il REPL, tuttavia, si applica dall'interno del modulo in cui stai lavorando.

Un modo semplice per eseguire il test dall'esterno è utilizzare test submodule. Per esempio:

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

Modificare i contratti e rieseguire in DrRacket, e si dovrebbe vedere i vostri contratti in vigore qui, dal momento che il modulo test qui viene trattato come un cliente esterno del contratto.


In alternativa, fare un altro file che require s la prima, e poi si può vedere l'effetto dei contratti anche lì. Se il primo file si chiama true-test.rkt, allora si può fare un altro modulo, e poi:

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

Danny Yoo ha dato una risposta eccellente. Volevo solo ampliarlo e notare che Racket ti offre maggiore flessibilità su dove viene applicato il tuo contratto (ad esempio, dove inserire il limite del contratto ). Ad esempio, è possibile utilizzare il define/contract modulo:

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

che stabilirà contratto di verifica tra la definizione di true? e tutti gli altri codici:

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

trovo define/contract particolarmente utile se voglio provare qualcosa relativi ai contratti al REPL, in cui non ho sempre un modulo. Tuttavia, contract-out è la raccomandazione predefinita poiché il controllo dei contratti ai limiti del modulo è di solito una buona scelta.