Function signatures
In this course (and in the
text)
each function definition is preceded by a signature
(interchangeably called contract) and a purpose comment.
Most of the signatures that we will use in this class can be captured by types
and checked by the computer. The informal syntax used by the text for signatures
is a close match to the formal syntax of types used by Typed Racket; and can
be copied with only small changes.
For example, the
text
gives the following signature, purpose statement, and header for the profit
function:
;; profit : number -> number
;; to compute the profit as the difference between revenue and costs
;; at some given ticket-price
(define (profit ticket-price) ...)
The use of ...
to specify an incomplete function body is not supported in
Typed Racket, so we give the function’s definition when we translate:
(: profit : Number -> Number)
;; to compute the profit as the difference between revenue and costs
;; at some given ticket-price
(define (profit ticket-price)
(- (revenue ticket-price)
(cost ticket-price)))
Notice that the only change that we had to make was to change number
to
Number
.
Variable definitions
Variable definitions should also be preceded by a type ascription. The syntax is essentially the same as for functions. For example:
(: e Real)
(define e (exp 1))
(The function exp
is built in, and gives the value of e raised to
the given power.)
Testing
DrRacket comes with a bundle of tools for testing. There are many of
these; the ones that are immediately useful to you are check-expect
and check-within
, for testing exact and inexact results,
respectively. (Other useful checks
are check-range
and
check-error
)
The check
tools are made available when you require typed/test-engine/racket-tests
at the beginning of your program. Once you have included
tests in your code, you will need to add the following command at the end
of your program:
(test)
This command will cause the tests to run.
For example, we can add tests for the sq
function that we defined above:
(: sq (-> Number Number))
;; return the square of a number
;;
(define (sq x)
(* x x))
(check-expect (sq 5) 25)
(check-expect (sq -1) 1)
When computing with real numbers, the results are often inexact. In that
situation we use the check-within
form to test if an expression evaluates to
within a given delta of an expected result.
(check-within expr-1 expr-2 delta-expr)
For example
(check-within (sq (sqrt 2)) 2 0.001)
Note that the test
function runs all of the tests defined up to its invocation.
Therefore, you should only invoke it once after all of the tests have been
defined.
Querying types
It is possible to query the type of an identifier using DrRacket’s REPL using
the :print-type
function:
> (:print-type sq)
(-> Number Number)
Notice that Typed Racket prints function types using the prefix syntax. Thus, even if you prefer the more natural infix arrow syntax when you write your own code, you will need to be comfortable with the prefix syntax as well.