<div dir="ltr"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">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.</blockquote>
<div><br></div><div>Why is it an abuse of the contract system to define a contract that uses a projection to change the value?†</div><div><br></div><div>The docs for make-contract say "The projection must either produce the value, <b>suitably wrapped to enforce any higher-order aspects of the contract</b>, 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?)</div>
<div><br></div><div>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.</div>
<div><br></div><div><div>(define coerce/path?</div><div>† (make-contract</div><div>† †#:name 'coerce/path?</div><div>† †#:projection (Ž (b)</div><div>† † † † † † † † † (Ž (x)</div><div>† † † † † † † † † † (if (can-be-path? x)</div>
<div>† † † † † † † † † † † † (convert-to-path x)</div><div>† † † † † † † † † † † † (raise-blame-error</div><div>† † † † † † † † † † † † †b x</div><div>† † † † † † † † † † † † †'(expected: "~a" given: "~e")</div>
<div>† † † † † † † † † † † † †'can-be-path? x))))))</div></div><div><br></div><div><br></div><div><br></div><div><br></div><div><br></div><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Nov 18, 2013 at 10:25 AM, Ryan Culpepper <span dir="ltr"><<a href="mailto:ryanc@ccs.neu.edu" target="_blank">ryanc@ccs.neu.edu</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class=""><div class="h5">On 11/18/2013 12:03 PM, Matthew Butterick wrote:<br>

<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
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?<br>
<br>
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:<br>

<br>
"#c00"<br>
"#cc0000"<br>
'("204" "0" "0")<br>
#xcc0000<br>
'(0.8 0 0)<br>
<br>
Let's say that my internal representation of an RGB color is described by the contract rgb-color/c:<br>
<br>
(define rgb-color/c (list/c (real-in 0 1) (real-in 0 1) (real-in 0 1)))<br>
<br>
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:<br>
<br>
(define (rgb-colorish? x) (or/c rgb-color/c [tests for the other input formats ...] )<br>
<br>
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.<br>
<br>
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.<br>
</blockquote>
<br></div></div>
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.<br>

<br>
But... by abusing the contract system a little bit, though, we can get it to do the conversion for you.<br>
<br>
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.<br>
<br>
> (define (make-named-conversion-<u></u>contract name convert)<br>
† † (define ((proj blame) v)<br>
† † † (cond [(convert v )<br>
† † † † † † †=> values]<br>
† † † † † † [else<br>
† † † † † † †(raise-blame-error blame v<br>
† † † † † † † † † † † † † † † † '(expected: "~a" given: "~e")<br>
† † † † † † † † † † † † † † † † name v)]))<br>
† † (make-contract #:name name #:projection proj))<br>
<br>
Here's a "contract" that checks that a value is real, and if so produces its absolute value.<br>
<br>
> (define abs/c<br>
† † (make-named-conversion-<u></u>contract<br>
† † †'abs/c<br>
† † †(lambda (v) (and (real? v) (abs v)))))<br>
<br>
And here's a function using the converting "contract":<br>
<br>
> (define/contract f (-> abs/c real?)<br>
† † (lambda (x) x))<br>
> (f 10)<br>
10<br>
> (f -12) † † † †;; <-- !!!<br>
12<br>
> (f 'hello)<br>
f: contract violation<br>
†expected: abs/c<br>
†given: 'hello<br>
†....<br>
<br>
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.<span class=""><font color="#888888"><br>

<br>
Ryan</font></span><div class=""><div class="h5"><br>
<br>
____________________<br>
†Racket Users list:<br>
†<a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/<u></u>users</a><br>
</div></div></blockquote></div><br></div></div>