Documented the optimizer.

original commit: cb516081c742cfeb04d754d4925389de33319cd7
This commit is contained in:
Vincent St-Amour 2010-08-02 10:35:17 -04:00
parent 492c89be8d
commit 83c6f99041

View File

@ -19,3 +19,92 @@ want to activate it, you must add the @racket[#:optimize] keyword when
specifying the language of your program:
@racketmod[typed/racket #:optimize]
@section{Getting the most out of the optimizer}
Typed Racket's optimizer can improve the performance of various common
Racket idioms. However, it does a better job on some idioms than on
others. By writing your programs using the right idioms, you can help
the optimizer help you.
@subsection{Numeric types}
Being type-driven, the optimizer makes most of its decisions based on
the types you assigned to your data. As such, you can improve the
optimizer's usefulness by writing informative types.
For example, the following programs both typecheck:
@racketblock[(define: (f (x : Real)) : Real (+ x 2.5))
(f 3.5)]
@racketblock[(define: (f (x : Float)) : Float (+ x 2.5))
(f 3.5)]
However, the second one uses more informative types: the
@racket[Float] type includes only inexact real numbers whereas the
@racket[Real] type includes both exact and inexact real numbers. Typed
Racket's optimizer can optimize the latter program to use
inexact-specific operations whereas it cannot do anything with the
former program.
Thus, to get the most of Typed Racket's optimizer, you should use the
@racket[Float] type when possible.
On a similar note, the @racket[Inexact-Complex] type is preferable to
the @racket[Complex] type for the same reason. Typed Racket can keep
inexact complex numbers unboxed; as such, programs using complex
numbers can have better performance than equivalent programs that
represent complex numbers as two real numbers. To get the most of
Typed Racket's optimizer, you should also favor rectangular
coordinates over polar coordinates.
@subsection{Lists}
Typed Racket handles potentially empty lists and lists that are known
to be non-empty differently: when taking the @racket[car] or the
@racket[cdr] of a list Typed Racket knows is non-empty, it can skip
the check for the empty list that is usually done when calling
@racket[car] and @racket[cdr].
@racketblock[
(define: (sum (l : (Listof Integer))) : Integer
(if (null? l)
0
(+ (car l) (sum (cdr l)))))
]
In this example, Typed Racket knows that if we reach the else branch,
@racket[l] is not empty. The checks associated with @racket[car] and
@racket[cdr] would be redundant and are eliminated.
In addition to explicitly checking for the empty list using
@racket[null?], you can inform Typed Racket that a list is non-empty
by using the known-length list type constructor; if your data is
stored in lists of fixed length, you can use the @racket[List] type
constructors.
For instance, the type of a list of two @racket[Integer]s can be
written either as:
@racketblock[(define-type List-2-Ints (Listof Integer))]
or as the more precise:
@racketblock[(define-type List-2-Ints (List Integer Integer))]
Using the second definition, all @racket[car] and @racket[cdr]-related
checks can be eliminated in this function:
@racketblock[
(define: (sum2 (l : List-2-Ints) : Integer)
(+ (car l) (car (cdr l))))
]
@subsection{Vectors}
In addition to known-length lists, Typed Racket supports known-length
vectors through the @racket[Vector] type constructor. Known-length
vector access using constant indices can be optimized in a similar
fashion as @racket[car] and @racket[cdr].
@#reader scribble/comment-reader (racketblock
;; #(name r g b)
(define-type Color (Vector String Integer Integer Integer))
(define: x : Color (vector "red" 255 0 0))
(vector-ref x 0) ; good
(define color-name 0)
(vector-ref x color-name) ; good
(vector-ref x (* 0 10)) ; bad
)