Virtually every Scheme program uses lists and sexpressions. Fortunately, Typed Scheme can handle these as well. A simple list processing program can be written like this:
(module add-list (planet "typed-scheme.ss" ("plt" "typed-scheme.plt")
)
(define: (sum-list [l : (Listof number)]) : number
(cond [(null? l) 0]
[else (+ (car l) (sum-list (cdr l)))])))
This looks similar to our earlier programs — except for the type
of l
, which looks like a function application. In fact, it’s
a use of the type constructor Listof
, which takes
another type as its input, here number
. We can use
Listof
to construct the type of any kind of list we might
want.
We can define our own type constructors as well. For example, here is an analog of the Maybe type constructor from Haskell:
(module maybe "typed-lang.ss" (define-typed-struct Nothing ()) (define-typed-struct (a) Just ([v : a])) (define-type-alias (Maybe a) (U Nothing (Just a))) (define: (find [v : number] [l : (Listof number)]) : (Maybe number) (cond [(null? l) (make-Nothing)] [(= v (car l)) (make-Just v)] [else (find v (cdr l))])))
The first define-typed-struct
defines Nothing
to be
a structure with no contents.
The second definition
(define-typed-struct (a) Just ([v : a]))
creates a parameterized type, Just
, which is a structure with
one element, whose type is that of the type argument to
Just
. Here the type parameters (only one, a
, in
this case) are written before the type name, and can be referred to in
the types of the fields.
The type alias definiton
(define-type-alias (Maybe a) (U Nothing (Just a)))
creates a parameterized alias — Maybe
is a potential
container for whatever type is supplied.
The find
function takes a number v
and list, and
produces (make-Just v)
when the number is found in the list,
and (make-Nothing)
otherwise. Therefore, it produces a
(Maybe number)
, just as the annotation specified.