Re: [racket-dev] Contract barrier inefficiencies

2012-12-28 Thread Robby Findler
By "selection" I mean applying a selector a struct value. Sorry, a bit too
terse, eh

As for the result, that looks like some great things for us to put into
benchmarks (or maybe the math library itself should be what we should look
at).

I think that the reason the profiler isn't helping you is because the time
you care about is being spent in the implementation of the primitives and
that's visible only at the C level. If you can run gprof (or Apple's
tools), you could probably see more of what's going on.

Overall, I feel like some of what you're asking has to do with what TR is
doing and some with what's going on inside the procedure chaperones and so
I'm not sure the contract library itself is a place where fixes can happen.
(But I didn't try to look into what exactly gets put into the chaperones by
the contract library to be sure of that -- maybe there is something dumb
happening there.)

Robby

On Fri, Dec 28, 2012 at 12:03 PM, Neil Toronto 
wrote:
>
> On 12/27/2012 06:21 PM, Robby Findler wrote:
>>
>> One other place that we realized pretty quickly where we were wrong
>> about the boundaries and inefficiencies is struct declarations. It isn't
>> uncommon to put contracts on structs and put them in their own module
>> (scribble does this). Currently the contract system can't tell that a
>> struct contract is actually on a struct and thus avoid checking when
>> doing a selection, but maybe that's somewhere that could help.
>
>
> What's a selection? Is it something I could understand by reading a
certain paper?
>
> Because using arrays for examples is pretty abstract and carries a lot of
baggage, I've made some independent examples that demonstrate the same
inefficiencies.
>
> The first uses Typed Racket to generate contracts. The type ((Vectorof
Index) -> A) corresponds with the type (Array A), and is in fact the type
of an array's procedure in `math/array'.
>
> In the following code, `make-array' makes an unbounded-ish, constant
"array". The `array-touch' function retrieves every element from 0 to n-1,
and throws them away.
>
>
> #lang racket
>
> (module typed-defs typed/racket/base
>   (require racket/fixnum racket/unsafe/ops)
>   (provide make-array array-touch)
>
>   (: make-array (All (A) (A -> ((Vectorof Index) -> A
>   (define (make-array e) (lambda (js) e))
>
>   (: array-touch (All (A) (((Vectorof Index) -> A) Index -> Void)))
>   (define (array-touch arr-proc n)
> (define: js : (Vectorof Index)  (vector 0))
> (let: loop : Void ([i : Nonnegative-Fixnum  0])
>   (when (i . fx< . n)  ; proves i : Index
> (unsafe-vector-set! js 0 i)
> (arr-proc js)
> (loop (fx+ i 1)
>
>   ;; Takes 20ms to call `arr-proc' 2 million times
>   (define arr-proc (make-array 10))
>   (time (for ([_  (in-range 200)])
>   (array-touch arr-proc 1
>
> (require 'typed-defs)
>
> ;; Takes 3300ms
> (define arr-proc (make-array 10))
> (time (for ([_  (in-range 200)])
> (array-touch arr-proc 1)))
>
>
> Summing up the numbers:
>  * inside loop: 20ms
>  * outside loop: 3300ms
>
> These numbers correspond with what I get using arrays in untyped code, so
this example probably isolates the main performance problems.
>
> Notice that `array-touch' mutates the indexes vector it passes to
`arr-proc'. The array library also does this in its nested loops over
elements to reduce allocation to one object (the mutated indexes vector).
Still, it's worth checking out what would happen if immutable vectors were
passed instead. If I'm reading "racket/contract/private/vector.rkt"
correctly, this could be faster because immutable vectors are checked
immediately instead of getting wrapped in a chaperone.
>
>   Changing (arr-proc js) to (arr-proc (vector->immutable-vector js)):
>* inside loop: 100ms
>* outside loop: 2950ms
>
> The "inside loop" timing is what I expected from my earlier experiments
that motivated using mutable indexes. The "outside loop" timing suggests
the chaperone isn't the biggest performance problem. (Of course, this
example doesn't even look at the chaperoned value.)
>
>   Changing (Vectorof Index) to (Vectorof Any): no change
>
> I think this is because the chaperone checks the contents of `js' only
when `js' is indexed - which never happens in this example.
>
>   Changing (Vectorof Index) to Any:
>* inside loop: 20ms (no change)
>* outside loop: 2200ms
>
> This suggests that putting any kind of contract on indexes is a big
performance hit, but not the biggest.
>
> There's not a lot left to investigate here without diving into TR's
internals, so here's an untyped version that uses contracts:
>
>
> #lang racket
>
> (module untyped-defs racket/base
>   (require racket/fixnum racket/unsafe/ops
>racket/contract (only-in typed/racket/base index?))
>   (provide
>(contract-out
> [make-array  (-> any/c (-> (vectorof index?) any/c))]
> [array-touch  (-> (-> (vectorof index?) any/c) index? void?)]))
>
>   (define (make-arr

Re: [racket-dev] Contract barrier inefficiencies

2012-12-28 Thread Vincent St-Amour
At Thu, 27 Dec 2012 19:21:53 -0600,
Robby Findler wrote:
> OC could suggest moving heavily called functions across boundaries, that'd
> be cool.

That sounds interesting, and would be a good use of profiling
information. Added to my to-do list.

Thanks for the suggestion!

Vincent
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] Contract barrier inefficiencies

2012-12-28 Thread Neil Toronto

On 12/27/2012 06:21 PM, Robby Findler wrote:

One other place that we realized pretty quickly where we were wrong
about the boundaries and inefficiencies is struct declarations. It isn't
uncommon to put contracts on structs and put them in their own module
(scribble does this). Currently the contract system can't tell that a
struct contract is actually on a struct and thus avoid checking when
doing a selection, but maybe that's somewhere that could help.


What's a selection? Is it something I could understand by reading a 
certain paper?


Because using arrays for examples is pretty abstract and carries a lot 
of baggage, I've made some independent examples that demonstrate the 
same inefficiencies.


The first uses Typed Racket to generate contracts. The type ((Vectorof 
Index) -> A) corresponds with the type (Array A), and is in fact the 
type of an array's procedure in `math/array'.


In the following code, `make-array' makes an unbounded-ish, constant 
"array". The `array-touch' function retrieves every element from 0 to 
n-1, and throws them away.



#lang racket

(module typed-defs typed/racket/base
  (require racket/fixnum racket/unsafe/ops)
  (provide make-array array-touch)

  (: make-array (All (A) (A -> ((Vectorof Index) -> A
  (define (make-array e) (lambda (js) e))

  (: array-touch (All (A) (((Vectorof Index) -> A) Index -> Void)))
  (define (array-touch arr-proc n)
(define: js : (Vectorof Index)  (vector 0))
(let: loop : Void ([i : Nonnegative-Fixnum  0])
  (when (i . fx< . n)  ; proves i : Index
(unsafe-vector-set! js 0 i)
(arr-proc js)
(loop (fx+ i 1)

  ;; Takes 20ms to call `arr-proc' 2 million times
  (define arr-proc (make-array 10))
  (time (for ([_  (in-range 200)])
  (array-touch arr-proc 1

(require 'typed-defs)

;; Takes 3300ms
(define arr-proc (make-array 10))
(time (for ([_  (in-range 200)])
(array-touch arr-proc 1)))


Summing up the numbers:
 * inside loop: 20ms
 * outside loop: 3300ms

These numbers correspond with what I get using arrays in untyped code, 
so this example probably isolates the main performance problems.


Notice that `array-touch' mutates the indexes vector it passes to 
`arr-proc'. The array library also does this in its nested loops over 
elements to reduce allocation to one object (the mutated indexes 
vector). Still, it's worth checking out what would happen if immutable 
vectors were passed instead. If I'm reading 
"racket/contract/private/vector.rkt" correctly, this could be faster 
because immutable vectors are checked immediately instead of getting 
wrapped in a chaperone.


  Changing (arr-proc js) to (arr-proc (vector->immutable-vector js)):
   * inside loop: 100ms
   * outside loop: 2950ms

The "inside loop" timing is what I expected from my earlier experiments 
that motivated using mutable indexes. The "outside loop" timing suggests 
the chaperone isn't the biggest performance problem. (Of course, this 
example doesn't even look at the chaperoned value.)


  Changing (Vectorof Index) to (Vectorof Any): no change

I think this is because the chaperone checks the contents of `js' only 
when `js' is indexed - which never happens in this example.


  Changing (Vectorof Index) to Any:
   * inside loop: 20ms (no change)
   * outside loop: 2200ms

This suggests that putting any kind of contract on indexes is a big 
performance hit, but not the biggest.


There's not a lot left to investigate here without diving into TR's 
internals, so here's an untyped version that uses contracts:



#lang racket

(module untyped-defs racket/base
  (require racket/fixnum racket/unsafe/ops
   racket/contract (only-in typed/racket/base index?))
  (provide
   (contract-out
[make-array  (-> any/c (-> (vectorof index?) any/c))]
[array-touch  (-> (-> (vectorof index?) any/c) index? void?)]))

  (define (make-array e) (lambda (js) e))

  (define (array-touch arr-proc n)
(define js (vector 0))
(let loop ([i 0])
  (when (i . unsafe-fx< . n)
(unsafe-vector-set! js 0 i)
(arr-proc js)
(loop (unsafe-fx+ i 1)

  (define arr-proc (make-array 10))
  (time (for ([_  (in-range 200)])
  (array-touch arr-proc 1

(require 'untyped-defs)

(define arr-proc (make-array 10))
(time (for ([_  (in-range 200)])
(array-touch arr-proc 1)))


The timings for the loops in this version are identical to those from 
the typed version: 20ms inside vs. 3300ms outside. But this is surprising:


  Changing (vectorof index?) to any/c:
   * inside loop: 20ms
   * outside loop: 1700ms

Doing the same thing in the typed version reduced the "outside loop" 
time to 2200ms, not 1700ms. It must not be the same thing after all. 
What's going on?


  Changing the "array" contract to (-> (vectorof index?) any):
   * inside loop: 20ms
   * outside loop: 2340ms

This suggests that checking for multiple values is pretty slow.

  Changing the "array" contract to (-> an

Re: [racket-dev] Feature request - contract form that splits provide/contract into two parts

2012-12-28 Thread Harry Spier
On Fri, Dec 28, 2012 at 9:42 AM, Matthias Felleisen
 wrote:

> 2. We see Racket as a continuum:
...
>, you should know which entry point is best for you
> and choose for yourself at which level you wish to enter. The
> point is
>
>   with Racket, you have this choice
>
> (and with other languages, you don't.) -- Matthias
>

Programming in Racket is an absolute delight.
Harry
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] Contract barrier inefficiencies

2012-12-28 Thread Neil Toronto

On 12/28/2012 08:23 AM, Matthias Felleisen wrote:

On Dec 27, 2012, at 9:22 PM, Neil Toronto wrote:

Sorry it took so long to reply.

I applied the patch and verified that my example runs a *lot* faster (with 
domain and range contracts identical, of course). Unfortunately, a similar test 
using arrays isn't any faster. This is how the identity function for arrays is 
defined in the test:

  (: array-id (All (A) ((Array A) -> (Array A
  (define (array-id arr) arr)


If we had macros for types, we might be able to write

  (All (A) (let ((t (Array A))) (t -> t)))


The change doesn't help because the contracts for each instance of (Array A) in 
the type aren't identical. Merging such contracts would be a great space 
optimization in general, but I don't know whether it would make using 
`math/array' from untyped code any faster.

Actually, right now, I'm sure it wouldn't help much. I can't think of any array 
functions that return an array with an identical procedure


It is not an identical procedure that makes for contract optimizations here but 
identical contracts/types. Would that help?


Hmm... it might, if the merging were thorough enough (i.e. merging 
contracts from different modules) or `contract-stronger?' were used. By 
the time an array is operated on in Typed Racket code, I think it's had 
its procedure wrapped with two equivalent higher-order contracts. An 
example:


#lang racket
(require math/array)

(define arr (make-array #(100 100) 0))
(array->mutable-array arr)

So `arr' has an (Array any/c) contract from being returned from 
`make-array' across the barrier. When `array->mutable-array' operates on 
it, it crosses the barrier again, so an (Array any/c) contract is applied.


What would be really nice is if passing the array back in to typed code 
*removed* the contract put on it coming out, or removed parts of it. For 
the array's procedure, the typed code needs a ((Vectorof Index) -> A). 
It gets a value with the contract ((vectorof index?) . -> . any/c). The 
typed code has been statically verified to not violate that contract. 
Would it be sound for the barrier to detect that and unwrap the value?


Neil ⊥


On 12/18/2012 12:04 PM, Robby Findler wrote:

I can't help with the others, but for 1.) I've considered using a
contract-stronger? test or even just an eq? test when applying a
contract, checking what's already on the value. I haven't added that as
it hasn't come up "in anger" (and it isn't free, but the check is
cheap). If I put a broken test (diff below) and adjust your example a
little bit, it runs quickly for me. Does it also help in your larger
context?

Adjustment:

(module defs racket
   (define c (any/c . -> . any/c))
   (provide (contract-out [fun-id  (-> c c)]))
   (define (fun-id f) f))

Diff:

[robby@wireless-165-124-98-86] ~/git/plt/collects/racket$ git diff . | cat
diff --git a/collects/racket/contract/private/arrow.rkt
b/collects/racket/contract/private/arrow.rkt
index 55ed632..63c9a6e 100644
--- a/collects/racket/contract/private/arrow.rkt
+++ b/collects/racket/contract/private/arrow.rkt
@@ -506,6 +506,10 @@ v4 todo:
 partial-mandatory-kwds
partial-optional-kwds
 partial-ranges))
(λ (val)
+(cond
+  [(eq? (value-contract val) ctc)
+   val]
+  [else
  (if has-rest?
  (check-procedure/more val mtd? dom-length
mandatory-keywords optional-keywords orig-blame)
  (check-procedure val mtd? dom-length optionals-length
mandatory-keywords optional-keywords orig-blame))
@@ -521,7 +525,7 @@ v4 todo:
   impersonator-prop:contracted ctc
   impersonator-prop:application-mark (cons contract-key
;; is this right?
-  partial-ranges)))
+
  partial-ranges)))])
  (define (->-name ctc)
(single-arrow-name-maker


The diff is broken because it doesn't account for blame. The test should
be making sure that the two contracts blame the same things
(alternatively, we could not check that and just drop the inner
contract. That may be better, but not as easy to try ...)

Robby


On Tue, Dec 18, 2012 at 12:06 PM, Neil Toronto mailto:neil.toro...@gmail.com>> wrote:

So there are potentially huge inefficiencies when mixing typed and
untyped code, usually when functions are passed across the contract
barrier. Here are a few things that I think cause them. Can the
People Who Know This Stuff Really Well please comment on these issues?


1. Functions that cross the contract barrier can have exactly the
same contract applied multiple times. Here's some benchmark code
that demonstrates the issue:

#lang racket

(module defs racket
   (provide (contract-out [fun-id  (-> (any/c . -> . any/c)
   (any/c . -> . any/c))]))
   (define (fun-i

Re: [racket-dev] Feature request - contract form that splits provide/contract into two parts

2012-12-28 Thread Ray Racine
An alternate flow which I think aligns slightly better with graduated code
validity vs cost (effort)?

0. Quick and dirty code spikes, snippets in R.
1. Write prototype code directly in TR.
  - Liberal addition via Step 0 efforts, pre and current with Step 1.
  - TR is very lightweight.
  - The single additional type line is negligible in effort and is the
singular most concise, effective expression of documentation that one can
put in their code.
  - The benefits of instant TR feedback in DR while coding, IMHO, far out
weight considerations of rapid prototyping without TR.
  - TR in effect is/should be eliding contracts where static type checking
can prove safe absence and implicitly inserting contracts contracts based
on safety settings.
2. If you like your prototype and you know it will be around awhile:
  - Selectively transform unchecked contracts into checked contracts
  - Add contracts which increase code robustness value with consideration
of performance overhead. *[1,2]

Essentially
Step 1: Write prototypes in statically typed code from the get go in TR.
Step 2: Turn prototypes into high quality code by adding runtime contracts.

[*1] Essentially considered effort by the programmer towards marked
enhancement of production/library code validity with all the
design-by-contract, pre/post assertions, IO boundary assertions, bounds
assertions, etc that a static type checker cannot handle.
[*2] The risk is that Step 2 is under appreciated and may not happen,
therefore an emphasis in starting in CR (Contract Racket) and then later
splitting contracts into orthogonal static (TR) and runtime (CR) proofing
of code validity, thus guaranteeing some effort in Step 2 happened at all.
 Step 1 in no way absolves the programmer of Step 2.



On Fri, Dec 28, 2012 at 9:42 AM, Matthias Felleisen wrote:

>
> On Dec 27, 2012, at 8:58 PM, Harry Spier wrote:
>
> > On Fri, Dec 14, 2012 at 10:44 AM, Matthias Felleisen
> >  wrote:
> >>
> >> It is critical to inform clients of the services that a module
> >> provides. In the absence of types, contracts are the closest
> >> information we have.
> > AND
> > On Fri, Dec 14, 2012 at 11:43 AM, Ray Racine 
> wrote:
> >> For the TR folks you can have your cake and eat it with a cup of coffee
> with
> >> `provide'.  TR Rules
> >
> > Given the above, should you be using Typed Racket instead of contracts
> > whenever possible?  Are there cases where if you have the choice you
> > should prefer contracts instead of using Typed Racket
>
>
> No for several reasons:
>
> 1. Our contracts are actually more powerful than our types:
>
>  see
> http://www.ccs.neu.edu/home/matthias/Style/style/Units_of_Code.html#(part._.Contracts)
>
> especially contract for celsius->fahrenheit for an example.
> (In principle, our type system can express this idea.)
>
> 2. We see Racket as a continuum:
>  -- write a script, throw it away
>  -- or grow the script/create prototype with informal contracts and data
> descriptions
>  -- if you like your prototype and you know it'll be around for a while,
> turn informal contracts into checked contracts
> weighing performance impact against importance of checks.
>  -- if you ever maintain any of these modules, split contracts into types
> and residual contracts.
> Problem: we still don't have contract-out for TR
> So you will need to turn contracts into types and throw away
> residual contracts.
>
> One day SAM will get around to this gap.
>
> 3. Of course, you should know which entry point is best for you
> and choose for yourself at which level you wish to enter. The
> point is
>
>   with Racket, you have this choice
>
> (and with other languages, you don't.) -- Matthias
>
>
> _
>   Racket Developers list:
>   http://lists.racket-lang.org/dev
>
_
  Racket Developers list:
  http://lists.racket-lang.org/dev


Re: [racket-dev] Contract barrier inefficiencies

2012-12-28 Thread Matthias Felleisen

On Dec 27, 2012, at 9:22 PM, Neil Toronto wrote:

> Sorry it took so long to reply.
> 
> I applied the patch and verified that my example runs a *lot* faster (with 
> domain and range contracts identical, of course). Unfortunately, a similar 
> test using arrays isn't any faster. This is how the identity function for 
> arrays is defined in the test:
> 
>  (: array-id (All (A) ((Array A) -> (Array A
>  (define (array-id arr) arr)


If we had macros for types, we might be able to write 

 (All (A) (let ((t (Array A))) (t -> t)))




> The change doesn't help because the contracts for each instance of (Array A) 
> in the type aren't identical. Merging such contracts would be a great space 
> optimization in general, but I don't know whether it would make using 
> `math/array' from untyped code any faster.
> 
> Actually, right now, I'm sure it wouldn't help much. I can't think of any 
> array functions that return an array with an identical procedure


It is not an identical procedure that makes for contract optimizations here but 
identical contracts/types. Would that help? 




> as one of the input arrays', except as a performance optimization. On the 
> other hand, some future code, possibly from someone else, might operate on 
> lists of arrays, and possibly return a shared tail. Merging equivalent 
> contracts (or using `contract-stronger?') would help, then.
> 
> Neil ⊥
> 
> On 12/18/2012 12:04 PM, Robby Findler wrote:
>> I can't help with the others, but for 1.) I've considered using a
>> contract-stronger? test or even just an eq? test when applying a
>> contract, checking what's already on the value. I haven't added that as
>> it hasn't come up "in anger" (and it isn't free, but the check is
>> cheap). If I put a broken test (diff below) and adjust your example a
>> little bit, it runs quickly for me. Does it also help in your larger
>> context?
>> 
>> Adjustment:
>> 
>> (module defs racket
>>   (define c (any/c . -> . any/c))
>>   (provide (contract-out [fun-id  (-> c c)]))
>>   (define (fun-id f) f))
>> 
>> Diff:
>> 
>> [robby@wireless-165-124-98-86] ~/git/plt/collects/racket$ git diff . | cat
>> diff --git a/collects/racket/contract/private/arrow.rkt
>> b/collects/racket/contract/private/arrow.rkt
>> index 55ed632..63c9a6e 100644
>> --- a/collects/racket/contract/private/arrow.rkt
>> +++ b/collects/racket/contract/private/arrow.rkt
>> @@ -506,6 +506,10 @@ v4 todo:
>> partial-mandatory-kwds
>> partial-optional-kwds
>> partial-ranges))
>>(λ (val)
>> +(cond
>> +  [(eq? (value-contract val) ctc)
>> +   val]
>> +  [else
>>  (if has-rest?
>>  (check-procedure/more val mtd? dom-length
>> mandatory-keywords optional-keywords orig-blame)
>>  (check-procedure val mtd? dom-length optionals-length
>> mandatory-keywords optional-keywords orig-blame))
>> @@ -521,7 +525,7 @@ v4 todo:
>>   impersonator-prop:contracted ctc
>>   impersonator-prop:application-mark (cons contract-key
>>;; is this right?
>> -  partial-ranges)))
>> +
>>  partial-ranges)))])
>>  (define (->-name ctc)
>>(single-arrow-name-maker
>> 
>> 
>> The diff is broken because it doesn't account for blame. The test should
>> be making sure that the two contracts blame the same things
>> (alternatively, we could not check that and just drop the inner
>> contract. That may be better, but not as easy to try ...)
>> 
>> Robby
>> 
>> 
>> On Tue, Dec 18, 2012 at 12:06 PM, Neil Toronto > > wrote:
>> 
>>So there are potentially huge inefficiencies when mixing typed and
>>untyped code, usually when functions are passed across the contract
>>barrier. Here are a few things that I think cause them. Can the
>>People Who Know This Stuff Really Well please comment on these issues?
>> 
>>
>>1. Functions that cross the contract barrier can have exactly the
>>same contract applied multiple times. Here's some benchmark code
>>that demonstrates the issue:
>> 
>>#lang racket
>> 
>>(module defs racket
>>   (provide (contract-out [fun-id  (-> (any/c . -> . any/c)
>>   (any/c . -> . any/c))]))
>>   (define (fun-id f) f))
>> 
>>(require 'defs)
>> 
>>(define (f x) x)
>> 
>>(define h
>>   (for/fold ([h f]) ([_  (in-range 1000)])
>> (fun-id h)))
>> 
>>(for ([_  (in-range 5)])
>>   (time (for ([_  (in-range 1000)])
>>   (h 5
>> 
>> 
>>I get over 800ms for each 1000 applications of `h', because it's
>>basically a 1000-deep wrapper. (Or is it 2000?)
>> 
>>(The contract system is smart enough to check the contract quickly
>>when the types are (any/c . -> . any), but I don't think TR ever
>>generates contracts usi

Re: [racket-dev] Feature request - contract form that splits provide/contract into two parts

2012-12-28 Thread Matthias Felleisen

On Dec 27, 2012, at 8:58 PM, Harry Spier wrote:

> On Fri, Dec 14, 2012 at 10:44 AM, Matthias Felleisen
>  wrote:
>> 
>> It is critical to inform clients of the services that a module
>> provides. In the absence of types, contracts are the closest
>> information we have.
> AND
> On Fri, Dec 14, 2012 at 11:43 AM, Ray Racine  wrote:
>> For the TR folks you can have your cake and eat it with a cup of coffee with
>> `provide'.  TR Rules
> 
> Given the above, should you be using Typed Racket instead of contracts
> whenever possible?  Are there cases where if you have the choice you
> should prefer contracts instead of using Typed Racket


No for several reasons: 

1. Our contracts are actually more powerful than our types: 

 see 
http://www.ccs.neu.edu/home/matthias/Style/style/Units_of_Code.html#(part._.Contracts)

especially contract for celsius->fahrenheit for an example. 
(In principle, our type system can express this idea.) 

2. We see Racket as a continuum: 
 -- write a script, throw it away 
 -- or grow the script/create prototype with informal contracts and data 
descriptions
 -- if you like your prototype and you know it'll be around for a while, 
turn informal contracts into checked contracts
weighing performance impact against importance of checks. 
 -- if you ever maintain any of these modules, split contracts into types and 
residual contracts. 
Problem: we still don't have contract-out for TR
So you will need to turn contracts into types and throw away residual 
contracts. 

One day SAM will get around to this gap. 

3. Of course, you should know which entry point is best for you 
and choose for yourself at which level you wish to enter. The 
point is

  with Racket, you have this choice

(and with other languages, you don't.) -- Matthias


_
  Racket Developers list:
  http://lists.racket-lang.org/dev