Confused about racket contracts

I defined a function true? for use with count in racket / list.

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

I noticed that I can provide numerical arguments, and my function will happily return #f .

 > (true? 6) #f 

So, I thought that I would investigate the use of the racket contract so that non-zero arguments would return an error in breach of contract. So I put this code in the tope file of my file:

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

However, after adding the contract, I still get the same behavior as mentioned above in the racket REPL. I don’t understand how it could be. What am I missing?

+8
racket
source share
2 answers

Contracts are usually executed between modules. So you have to try it from an external point of view. However, REPL is used inside the module in which you work.

An easy way to test from the outside is to use a test submodule . For example:

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

Change the contracts and re-run in DrRacket, and you will see your contracts here, since the test module here is considered as an external client of the contract.


Alternatively, make another file that require first, and you will also see the effect of the contracts. If the first file is called true-test.rkt , you can create another module, and then:

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

Danny Yu gave a great answer. I just wanted to expand it and note that Racket gives you more flexibility about where your contract is concluded (for example, where to put the border of the contract). For example, you can use the define/contract form:

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

which will set contract validation between true? and all other code:

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

I find define/contract especially useful if I want to check something related to contracts in REPL, where I don't always have a module. However, contract-out is the default recommendation because checking contracts at module boundaries is usually a good choice.

+13
source share

All Articles