14
14
@defmodule[typed/racket/contract]
15
15
16
16
Typed Racket supports contract programming using the
17
- @racketmodname[racket/contract] library. This section covers the
18
- contract-specific features of the type system as well as the functionality
19
- currently supported in Typed Racket.
17
+ @racketmodname[racket/contract] library. For Racket programmers that
18
+ want to migrate a module and its contracts to Typed Racket, the first
19
+ section walks through that process. That example also serves to
20
+ introduce some of the contract-specific features in the type system.
21
+
22
+ The remaining sections give more detail about the type system and
23
+ document support for Racket's contract library.
24
+
25
+ @section{Introduction: Migrating a Racket module 's contracts}
26
+
27
+ The function @racket[g] in this Racket module is provided to clients
28
+ with a contract
29
+ @;contract adapted from the intro of Findler, Felleisen 2002
30
+ @racketmod[racket
31
+ (provide
32
+ (contract-out
33
+ [g (-> (-> (and/c exact-integer? (>/c 9 ))
34
+ (and/c exact-integer? (between/c 0 99 )))
35
+ (and/c exact-integer? (between/c 0 99 )))]))
36
+ (define (g proc)
37
+ @#,(elem "... " ))]
38
+
39
+ Clients must call @racket[g] with a procedure, and when that procedure
40
+ is called with an integer larger than 9 it must return an integer
41
+ between 0 and 99. Given such a procedure, @racket[g] itself must
42
+ return an integer between 0 and 99 , too. If any of the requirements
43
+ aren't upheld, an error is raised, identifying where and when the
44
+ requirement was broken.
45
+
46
+ Programmers can migrate their module and its contracts to Typed
47
+ Racket. A typed version of the previous example might look like
48
+ @racketmod[typed/racket
49
+ (provide
50
+ (contract-out
51
+ [g (->/c (->/c (and/c exact-integer? (>/c 9 ))
52
+ (and/c exact-integer? (between/c 0 99 )))
53
+ (and/c exact-integer? (between/c 0 99 )))]))
54
+ (: g (-> (-> Integer Integer) Integer))
55
+ (define (g proc)
56
+ @#,(elem "... " ))]
57
+
58
+ Typed Racket's type system makes some of these contracts redundant.
59
+ All of the @racket[exact-integer?] contracts, for example, are implied
60
+ by @racket[g]'s type. So let 's replace the whole @racket[->/c]
61
+ contract with the following simpler one
62
+ @racketblock[(->/c (->/c (>/c 9 ) (between/c 0 99 ))
63
+ (between/c 0 99 ))]
64
+
65
+ Before digging into how the type system allows us to replace the first
66
+ contract with the second one, let 's briefly talk about contracts and
67
+ their types.
68
+
69
+ Because arbitrary (typed) functions can be used as part of a contract
70
+ in Typed Racket, contract types ensure that that function's type
71
+ requirements aren't violated. If the @racket[even?] function is used
72
+ as a contract , for example, its contract type guarantees that it will
73
+ only be applied to @racket[Integers]. If the contract system didn't
74
+ have higher-order contracts, then something similar to function types
75
+ would likely be sufficient to ensure that @racket[even?] wasn't
76
+ misused. Higher-order contracts, though, need an extended type
77
+ system that treats contract application different from function
78
+ application.
79
+
80
+ The type of the first contract is
81
+ @ex[#:label #f
82
+ (->/c (->/c (and/c exact-integer? (>/c 9 ))
83
+ (and/c exact-integer? (between/c 0 99 )))
84
+ (and/c exact-integer? (between/c 0 99 )))]
85
+ while the type of the second contract is
86
+ @ex[#:label #f
87
+ (->/c (->/c (>/c 9 ) (between/c 0 99 ))
88
+ (between/c 0 99 ))]
20
89
21
90
@section{Types}
22
91
92
+ As shown in the introduction, adding types to Racket's higher-order
93
+ contracts requires extending Typed Racket with new kinds of types.
94
+
23
95
@defform[#:kind "type "
24
96
(Contract [in type] [out type])]{
25
97
A contract can only be attached to values that satisfy its @racket[in] type,
@@ -30,19 +102,21 @@ currently supported in Typed Racket.
30
102
31
103
The result's type is a lower-bound of @racket[out] and @racket[t] with respect
32
104
to the precision order, which is like the subtype order. It differs in that it
33
- lacks contravariance in negative positions such as function domains.
105
+ lacks contravariance in negative positions such as function domains. As odd as
106
+ this may sound, it's OK for the same reason that Typed Racket can cast a
107
+ function from @racket[(-> Integer Integer)] to @racket[(-> Natural Natural)].
34
108
35
- @racket[Contract] is the most general type for contracts.
109
+ @racket[Contract] is the most general type constructor for contracts.
36
110
}
37
111
38
112
@defform[#:kind "type "
39
113
(FlatContract [in type] [out type])]{
40
114
This type is like @racket[Contract] but corresponds to @tech{flat contracts}. All
41
- @racket[FlatCon] contracts have a corresponding @racket[Contract] type. For
115
+ @racket[FlatContract] have a corresponding @racket[Contract] type. For
42
116
example, a @racket[(FlatContract Real Real)] is also a @racket[(Contract Real Real)].
43
117
44
- A contract with @racket[FlatCon ] type can be used as a function having domain
45
- type @racket[in].
118
+ A contract with @racket[FlatContract ] type can be used as a function
119
+ having domain type @racket[in].
46
120
47
121
Ordinary Racket @tech[#:key "contracts " ]{values coercible to a contract }, such
48
122
as integers, do not have this type. Coercing such values of type @racket[T] to
0 commit comments