/collects/typed-scheme/scribblings/guide/more.scrbl

http://github.com/gmarceau/PLT · Racket · 164 lines · 111 code · 53 blank · 0 comment · 2 complexity · 00eb70b39bde678b18c8393d8281b3b1 MD5 · raw file

  1. #lang scribble/manual
  2. @begin[(require "../utils.rkt"
  3. scribble/core scribble/eval
  4. (for-label (only-meta-in 0 typed/racket)
  5. (only-in mzlib/etc let+)))]
  6. @title[#:tag "more"]{Specifying Types}
  7. @(define the-eval (make-base-eval))
  8. @(the-eval '(require typed/racket))
  9. The previous section introduced the basics of the Typed Racket type
  10. system. In this section, we will see several new features of the
  11. language, allowing types to be specified and used.
  12. @section{Type Annotation and Binding Forms}
  13. In general, variables in Typed Racket must be annotated with their
  14. type.
  15. @subsection{Annotating Definitions}
  16. We have already seen the @racket[:] type annotation form. This is
  17. useful for definitions, at both the top level of a module
  18. @racketblock[
  19. (: x Number)
  20. (define x 7)]
  21. and in an internal definition
  22. @racketblock[
  23. (let ()
  24. (: x Number)
  25. (define x 7)
  26. (add1 x))
  27. ]
  28. In addition to the @racket[:] form, almost all binding forms from
  29. @racketmodname[racket] have counterparts which allow the specification
  30. of types. The @racket[define:] form allows the definition of variables
  31. in both top-level and internal contexts.
  32. @racketblock[
  33. (define: x : Number 7)
  34. (define: (id [z : Number]) : Number z)]
  35. Here, @racket[x] has the type @racket[Number], and @racket[id] has the
  36. type @racket[(Number -> Number)]. In the body of @racket[id],
  37. @racket[z] has the type @racket[Number].
  38. @subsection{Annotating Local Binding}
  39. @racketblock[
  40. (let: ([x : Number 7])
  41. (add1 x))
  42. ]
  43. The @racket[let:] form is exactly like @racket[let], but type
  44. annotations are provided for each variable bound. Here, @racket[x] is
  45. given the type @racket[Number]. The @racket[let*:] and
  46. @racket[letrec:] are similar. Annotations are optional with
  47. @racket[let:] and variants.
  48. @racketblock[
  49. (let-values: ([([x : Number] [y : String]) (values 7 "hello")])
  50. (+ x (string-length y)))
  51. ]
  52. The @racket[let*-values:] and @racket[letrec-values:] forms are similar.
  53. @subsection{Annotating Functions}
  54. Function expressions also bind variables, which can be annotated with
  55. types. This function expects two arguments, a @racket[Number] and a
  56. @racket[String]:
  57. @racketblock[(lambda: ([x : Number] [y : String]) (+ x 5))]
  58. This function accepts at least one @racket[String], followed by
  59. arbitrarily many @racket[Number]s. In the body, @racket[y] is a list
  60. of @racket[Number]s.
  61. @racketblock[(lambda: ([x : String] (unsyntax @tt["."]) [y : Number #,**]) (apply + y))]
  62. This function has the type @racket[(String Number #,** -> Number)].
  63. Functions defined by cases may also be annotated:
  64. @racketblock[(case-lambda: [() 0]
  65. [([x : Number]) x])]
  66. This function has the type
  67. @racket[(case-lambda (-> Number) (Number -> Number))].
  68. @subsection{Annotating Single Variables}
  69. When a single variable binding needs annotation, the annotation can be
  70. applied to a single variable using a reader extension:
  71. @racketblock[
  72. (let ([#,(annvar x Number) 7]) (add1 x))]
  73. This is equivalent to the earlier use of @racket[let:]. This is
  74. especially useful for binding forms which do not have counterparts
  75. provided by Typed Racket, such as @racket[let+]:
  76. @racketblock[
  77. (let+ ([val #,(annvar x Number) (+ 6 1)])
  78. (* x x))]
  79. @subsection{Annotating Expressions}
  80. It is also possible to provide an expected type for a particular
  81. expression.
  82. @racketblock[(ann (+ 7 1) Number)]
  83. This ensures that the expression, here @racket[(+ 7 1)], has the
  84. desired type, here @racket[Number]. Otherwise, the type checker
  85. signals an error. For example:
  86. @interaction[#:eval the-eval
  87. (ann "not a number" Number)]
  88. @section{Type Inference}
  89. In many cases, type annotations can be avoided where Typed Racket can
  90. infer them. For example, the types of all local bindings using
  91. @racket[let] and @racket[let*] can be inferred.
  92. @racketblock[(let ([x 7]) (add1 x))]
  93. In this example, @racket[x] has the type
  94. @racket[Exact-Positive-Integer].
  95. Similarly, top-level constant definitions do not require annotation:
  96. @racketblock[(define y "foo")]
  97. In this examples, @racket[y] has the type @racket[String].
  98. Finally, the parameter types for loops are inferred from their initial
  99. values.
  100. @racketblock[
  101. (let loop ([x 0] [y (list 1 2 3)])
  102. (if (null? y) x (loop (+ x (car y)) (cdr y))))]
  103. Here @racket[x] has the inferred type @racket[Integer], and @racket[y]
  104. has the inferred type @racket[(Listof Integer)]. The @racket[loop]
  105. variable has type @racket[(Integer (Listof Integer) -> Integer)].
  106. @section{New Type Names}
  107. Any type can be given a name with @racket[define-type].
  108. @racketblock[(define-type NN (Number -> Number))]
  109. Anywhere the name @racket[NN] is used, it is expanded to
  110. @racket[(Number -> Number)]. Type names may not be recursive.
  111. @(close-eval the-eval)