[racket] Understanding contracts
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
>
>