2013-02-05 12 views
8

Zdefiniowałem funkcję true? do użytku z count w rakiecie/liście.Mylić o umów rakietowych

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

zauważyłem mogę dostarczyć argumentów liczbowych i moja funkcja chęcią powrócimy #f.

> (true? 6) 
#f 

Tak, myślałem, że chciałbym zbadać stosując umowę rakietę, aby non-logiczne o argumenty zwróci błąd z naruszeniem umowy. Więc umieścić ten kod na Tope mojego pliku:

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

Jednak po dodaniu kontrakt ja wciąż takie samo zachowanie jak wyżej w REPL rakieta. Nie rozumiem, jak to możliwe. czego mi brakuje?

+2

Pamiętaj, że w twoim konkretnym kontekście możesz użyć "wartości", ponieważ Racket traktuje wszystko jako prawdziwe, z wyjątkiem '# f'. Np .: '(count count '(ile #f true #f #f things #f))' – dyoo

Odpowiedz

20

Kontrakty są zwykle egzekwowane między modułami. Więc musisz spróbować z zewnątrz. REPL ma jednak zastosowanie z wnętrza modułu, w którym pracujesz.

Łatwym sposobem testowania z zewnątrz jest użycie test submodule. Na przykład:

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

Zmiany kontrakty i ponownie uruchomić w DrRacket, i powinieneś zobaczyć swoje kontrakty w efekcie tutaj, ponieważ moduł test tutaj jest traktowany jako zewnętrzny klienta zamówienia.


Ewentualnie dokonać innego pliku, który require ów pierwszy, a następnie można zobaczyć efekt umów tam. Jeśli pierwszy plik nazywa true-test.rkt, wówczas można dokonać innego modułu, a następnie:

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

Danny Yoo dał doskonałą odpowiedź. Chciałem po prostu rozwinąć to i zauważyć, że Rakieta daje ci większą elastyczność w miejscu egzekwowania Twojej umowy (tj. Gdzie umieścić granicę kontraktową ). Na przykład, możesz skorzystać z formularza define/contract:

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

która ustanowi sprawdzanie umowa między definicją true? i wszystkich innych kodu:

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

znajdę define/contract szczególnie przydatna, gdy chcę przetestować coś związane z umowami w REPL, gdzie nie zawsze mam moduł. Jednak zalecenie domyślne to contract-out, ponieważ sprawdzanie umów na granicach modułów jest zwykle dobrym wyborem.

Powiązane problemy