2013-02-05 21 views
8

count raket/listede kullanılmak üzere true? işlevini tanımladım. Raket sözleşmeleri hakkında karışıklık

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

ben bunu sayısal argümanlar sağlayabilir ve benim işlevi mutlu #f döneceğini fark ettim.

> (true? 6) 
#f 

Yani, ben olmayan boolean argümanlar sözleşme aşarak bir hata döndürür yapmak için bir raket sözleşme kullanarak keşfetmek düşündüm. Yani benim dosyanın tope bu kodu koymak:

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

Ancak, ben hala raket repl yukarıdaki ile aynı davranışı elde sözleşme ekledikten sonra. Bunun nasıl olabileceğini anlamıyorum. Neyi kaçırıyorum?

+2

Not: Bağlam, bağlamınız için 'değerler'i kullanabilir, çünkü Racket her şeyi # f 'dışında herşeyi true olarak kabul eder. E.g .: '(sayı değerleri '(#f true #f #f #f şeyler #f))' – dyoo

cevap

20

Sözleşmeler genellikle modülleri arasında zorlanır. Yani bunu dışarıdan bakmanız gerekiyor. Ancak, REPL, içinde çalıştığınız modülün içinden uygulanır.

Dıştan test yapmanın kolay bir yolu, test submodule kullanmaktır. Örneğin:

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

Değişim sözleşmeleri ve DrRacket yeniden çalıştırın ve burada test modül sözleşme harici müşteri olarak tedavi ediliyor olduğundan, buradaki yürürlükte Anlaşmalarınızı görmelisiniz.


Alternatif require ilk o başka bir dosya olun ve sonra orada çok sözleşmelerin etkisini görebilirsiniz. İlk dosya true-test.rkt denir, o zaman daha sonra başka bir modül şekilde görünmesini sağlayabilirsiniz:

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

Danny Yoo mükemmel bir cevap verdi. Sadece genişletmek istedim ve Racket'in sözleşmenizin uygulandığı yere (yani sözleşme sınırı'u nereye koyacağınız) daha fazla esneklik sağladığını not ettim. Bir şey test etmek istiyorsanız ben özellikle yararlı define/contract bulmak

-> (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 (true? expr) 
    (-> boolean? boolean?) 
    (and (boolean? expr) expr #t)) 

sözleşme true? tanımı ve diğer tüm kodu arasında kontrol kuracak: Örneğin, define/contract formu kullanabilirsiniz Her zaman bir modülün olmadığı REPL'teki sözleşmelerle ilgili. Bununla birlikte, contract-out varsayılan öneridir çünkü modül sınırlarındaki kontratların kontrolü genellikle iyi bir seçimdir.