[racket] Understanding contracts

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Thu Oct 2 14:36:20 EDT 2014

If you use this as the program: 

#lang racket

;; contracts set up boundaries between two regions of a program, say two modules 

;; ---------------------------------------------------------------------------------------------------
;; the library 
(provide (contract-out
           [struct bezier-control-point ((x (and/c number? (between/c 0 1))) (y number?))]
           [cubic-bezier (-> bezier-control-point? 
                             bezier-control-point?
                             (->* ((and/c number? (between/c 0 1)))
			          (#:clamp-range boolean?)
                                  number?))]))

(struct bezier-control-point (x y) #:transparent)

(define (cubic-bezier a b)
  ;; now produce a curve via Bezier triangulation
  (lambda (x #:clamp-range [cr #f])
    x))

;; ---------------------------------------------------------------------------------------------------
;; the module that uses it 
(module+ test
 (require (submod ".."))

 (define a (bezier-control-point 0.1 5.0))
 (define b (bezier-control-point 0.3 9.0))

 ((cubic-bezier a b) 
  ;; a contract violation because i isn't comparable 
  (sqrt -1)))


drracket or raco test file.rkt will show contract errors. 




On Oct 2, 2014, at 1:50 PM, Alexander McLin <alex.mclin at gmail.com> wrote:

> Spencer, I'm calling cubic-bezier from within a (module+ test (require submod "..")...) form that itself is defined in the file where cubic-bezier is defined. Also I tried from within REPL and requiring the code file.
> 
> Matthias,
> 
> I ran your example and it works exactly the way I wanted. The lambda returned from cubic-bezier properly raises contract violations when bad inputs are given for the required parameter and optional keyword.
> 
> Examining the differences between your example and my original implementation, my functions are directly defined in top level in the file, after #lang racket, not wrapped within a module. And I'm running my test cases within a (module+ test (require submod "..")) form.
> 
> In my test cases within (module+ test...), violations are correctly reported when I give bad inputs to cubic-bezier and bezier-control-point structs. Except the lambda, no violations are reported with bad inputs. Is it because I'm incorrectly using modules? I had thought that module+ and (require submod "..") would allow the contract system to come into full force.
> 
> 
> 
> On Thu, Oct 2, 2014 at 9:20 AM, Matthias Felleisen <matthias at ccs.neu.edu> wrote:
> 
> Let's make Spencer's question concrete. Say we have this situation:
> 
> #lang racket
> 
> ;; contracts set up boundaries between two regions of a program, say two modules
> 
> ;; ---------------------------------------------------------------------------------------------------
> ;; the library
> (module server racket
>   (provide (contract-out
>             [struct bezier-control-point ((x (and/c number? (between/c 0 1))) (y number?))]
>             [cubic-bezier (-> bezier-control-point?
>                               bezier-control-point?
>                               (->* ((and/c number? (between/c 0 1)))
>                                    (#:clamp-range boolean?)
>                                    number?))]))
> 
>   (struct bezier-control-point (x y) #:transparent)
> 
>   (define (cubic-bezier a b)
>     ;; now produce a curve via Bezier triangulation
>     (lambda (x #:clamp-range [cr #f])
>       x)))
> 
> ;; ---------------------------------------------------------------------------------------------------
> ;; the module that uses it
> (module client racket
>   (require (submod ".." server))
> 
>   (define a (bezier-control-point 0.1 5.0))
>   (define b (bezier-control-point 0.3 9.0))
> 
>   ((cubic-bezier a b)
>    ;; a contract violation because i isn't comparable
>    (sqrt -1)))
> 
> ;; ---------------------------------------------------------------------------------------------------
> ;; run program run
> (require 'client)
> 
> I assume you want to see other violations. Can you explain with this example w/o going into Bezier?
> (I just know enough about Bezier to draw curves.)
> 
> -- Matthias
> 
> 
> 
> 
> On Oct 1, 2014, at 10:46 PM, Alexander McLin <alex.mclin at gmail.com> wrote:
> 
> > Hello,
> >
> > I've been working on a sample project to better understand how to use the contract system. I created a simple Bezier curve implementation and am using (provide (contract-out...) to attach contracts to the provided bindings.
> >
> > Basically I have a procedure called cubic-bezier that accepts two control point structs used to define the curve. It returns another procedure that actually generates the curve, it accepts an integer parameter that lies on [0, 1] and an optional keyword #:clamp-range. The generator procedure returns a number.
> >
> > The control point structure is a simple posn type that accepts X and Y fields where X must be between 0 and 1, and Y is allowed to be any number.
> >
> > Here are the contracts I defined provisionally:
> >
> > (provide (contract-out
> >           [struct bezier-control-point ((x (and/c number? (between/c 0 1)))
> >                                                       (y number?))]
> >           [cubic-bezier (-> bezier-control-point?
> >                                      bezier-control-point?
> >                                     (->* ((and/c number? (between/c 0 1)))
> >                                            (#:clamp-range boolean?)
> >                                            number?))]))
> >
> > For the contract attached to cubic-bezier using ->, my thinking was to use ->* to generate the contract for the procedure returned by cubic-bezier but it's not working, meaning I'm not getting the any contract violations I'm expecting when giving bad inputs to cubic-bezier's value.
> >
> > How can I attach a more complex contract to cubic-bezier's value?
> >
> > Thank you
> > Alexander McLin
> > ____________________
> >  Racket Users list:
> >  http://lists.racket-lang.org/users
> 
> 



Posted on the users mailing list.