> > Of course, these are not really contracts as we understand them. The docs > for 'make-contract' say not to do this, if you read them carefully. So > beware. I'm kind of curious what other people think of this application of > the contract system, actually.
Why is it an abuse of the contract system to define a contract that uses a projection to change the value? The docs for make-contract say "The projection must either produce the value, *suitably wrapped to enforce any higher-order aspects of the contract*, or signal a contract violation." Is it never true that changing a value can be the "suitable wrapping"? (Or m I overlooking some other relevant part of the docs?) Consider this contract. It checks whether a value can be converted to a path. If so, it returns the converted value. If not, it fails. (This one's in quasicode, but I wrote a real one and it works as expected.) If this is abuse, it's very useful abuse. (define coerce/path? (make-contract #:name 'coerce/path? #:projection (λ (b) (λ (x) (if (can-be-path? x) (convert-to-path x) (raise-blame-error b x '(expected: "~a" given: "~e") 'can-be-path? x)))))) On Mon, Nov 18, 2013 at 10:25 AM, Ryan Culpepper <ry...@ccs.neu.edu> wrote: > On 11/18/2013 12:03 PM, Matthew Butterick wrote: > >> In a function that permits liberal inputs, I often find that the input >> processing I do in a contract is duplicated at the beginning of the body of >> the function. Is this avoidable? >> >> Certain functions want to be liberal with input because there are >> multiple common ways to represent the data. For instance, I have a function >> that operates on CSS RGB colors. This function should be prepared to accept >> these forms of input & understand that they're all the same: >> >> "#c00" >> "#cc0000" >> '("204" "0" "0") >> #xcc0000 >> '(0.8 0 0) >> >> Let's say that my internal representation of an RGB color is described by >> the contract rgb-color/c: >> >> (define rgb-color/c (list/c (real-in 0 1) (real-in 0 1) (real-in 0 1))) >> >> But I can't use rgb-color/c as the input contract for the function >> because it's too narrow. So I make a second contract that tests for things >> that can be converted to an rgb-color: >> >> (define (rgb-colorish? x) (or/c rgb-color/c [tests for the other input >> formats ...] ) >> >> To determine if the input is rgb-colorish?, this contract usually just >> ends up trying to convert the input to rgb-color. If it works, then the >> contract returns true. >> >> But after the contract returns, I have to convert the input to an >> rgb-color anyhow. So I'm doing exactly the same work that the contract just >> finished. If the conversion is expensive, I'm doing it twice. >> > > We usually just don't worry about the conversion happening twice. Or we do > what Matthias said. Or we apply a fast approximate contract (or none at > all) and then do the conversion and error checking together inside the > function. > > But... by abusing the contract system a little bit, though, we can get it > to do the conversion for you. > > Here's a "contract" combinator that takes a conversion function that > returns #f to indicate failure/rejection and any other value to represent > the converted result. > > > (define (make-named-conversion-contract name convert) > (define ((proj blame) v) > (cond [(convert v ) > => values] > [else > (raise-blame-error blame v > '(expected: "~a" given: "~e") > name v)])) > (make-contract #:name name #:projection proj)) > > Here's a "contract" that checks that a value is real, and if so produces > its absolute value. > > > (define abs/c > (make-named-conversion-contract > 'abs/c > (lambda (v) (and (real? v) (abs v))))) > > And here's a function using the converting "contract": > > > (define/contract f (-> abs/c real?) > (lambda (x) x)) > > (f 10) > 10 > > (f -12) ;; <-- !!! > 12 > > (f 'hello) > f: contract violation > expected: abs/c > given: 'hello > .... > > Of course, these are not really contracts as we understand them. The docs > for 'make-contract' say not to do this, if you read them carefully. So > beware. I'm kind of curious what other people think of this application of > the contract system, actually. > > Ryan > > > ____________________ > Racket Users list: > http://lists.racket-lang.org/users >
____________________ Racket Users list: http://lists.racket-lang.org/users