[racket] Understanding contracts

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

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.