2013-02-05 37 views
8

Tôi đã xác định một hàm true? để sử dụng với count trong vợt/danh sách.Bối rối về các hợp đồng vợt

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

Tôi nhận thấy tôi có thể cung cấp đối số dạng số và hàm của tôi vui vẻ trả về #f.

> (true? 6) 
#f 

Vì vậy, tôi nghĩ tôi sẽ khám phá bằng cách sử dụng một hợp đồng vợt để làm cho các đối số không logic trả về lỗi trong vi phạm hợp đồng. Vì vậy, tôi đặt mã này tại hình chữ nhật của tệp của tôi:

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

Tuy nhiên, sau khi thêm hợp đồng, tôi vẫn nhận được hành vi tương tự như trên trong vợt REPL. Tôi không hiểu nó có thể thế nào. Tôi đang thiếu gì?

+2

Lưu ý rằng đối với ngữ cảnh cụ thể của bạn, bạn có thể sử dụng 'giá trị', vì Racket coi mọi thứ là đúng trừ' # f'. Ví dụ: '(giá trị đếm '(số lượng #f đúng #f #f thứ #f))' – dyoo

Trả lời

20

Hợp đồng thường được thực thi giữa các mô-đun. Vì vậy, bạn sẽ phải thử nó từ quan điểm bên ngoài. Tuy nhiên, REPL áp dụng từ bên trong mô-đun mà bạn đang làm việc.

Cách dễ dàng để kiểm tra từ bên ngoài là sử dụng test submodule. Ví dụ:

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

Thay đổi hợp đồng và chạy lại trong DrRacket, và bạn sẽ thấy hợp đồng của bạn có hiệu lực ở đây, kể từ khi test mô-đun ở đây đang được coi là một khách hàng bên ngoài của hợp đồng.


Ngoài ra, hãy tạo một tệp khác là require s trước tiên, sau đó bạn có thể thấy hiệu quả của hợp đồng ở đó. Nếu tệp đầu tiên được gọi là true-test.rkt, thì bạn có thể tạo một mô-đun khác và sau đó:

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

Danny Yoo đã đưa ra một câu trả lời tuyệt vời. Tôi chỉ muốn mở rộng trên đó và lưu ý rằng Racket cung cấp cho bạn sự linh hoạt hơn về nơi hợp đồng của bạn được thực thi (tức là, nơi đặt ranh giới hợp đồng ). Ví dụ, bạn có thể sử dụng define/contract dạng:

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

đó sẽ thiết lập hợp đồng kiểm tra giữa định nghĩa của true? và tất cả các mã khác:

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

tôi thấy define/contract đặc biệt hữu ích nếu tôi muốn thử nghiệm một cái gì đó liên quan đến các hợp đồng tại REPL, nơi tôi không luôn có một mô-đun. Tuy nhiên, contract-out là đề xuất mặc định vì việc kiểm tra hợp đồng ở ranh giới mô-đun thường là một lựa chọn tốt.

Các vấn đề liên quan