Next: , Previous: , Up: annotations   [Contents][Index]


2.2 The syntax of type annotations

Type annotations are either standalone type identifiers like <fixnum>, <string>, &message or compound type syntaxes like the following:

(pair      <fixnum> <string>)
(list      <fixnum> <string> <symbol>)
(vector    <fixnum> <string> <symbol>)
(pair-of   <fixnum>)
(list-of   <fixnum>)
(nelist-of <fixnum>)
(vector-of <fixnum>)
(nevector-of <fixnum>)
(hashtable <symbol> <string>)
(alist     <symbol> <string>)
(enumeration ?symbol0 ?symbol ...)
(condition &who &message &irritants)
(or    <false> <symbol> <string>)
(and   <exact> <positive>)
(not   <exact>)
(maybe <string>)
(lambda (<fixnum>) => (<string>))
(case-lambda
  ((<fixnum>) => (<string>))
  ((<flonum>) => (<string>)))
(type-of ?expr)

and others; compound type annotations can be nested at will:

(or (list-of   <fixnum>)
    (vector-of <fixnum>))

For every type annotation: a parent type is documented, but the super–type/sub–type relation is “flexible”. For example, list-of and list annotations are both sub–types of <list>; but it also stands that:

(type-annotation-super-and-sub? (list-of <fixnum>)
                                (list <fixnum> <fixnum>))
⇒ #t

(type-annotation-super-and-sub? (list-of <fixnum>)
                                (list <fixnum> <string>))
⇒ #f

The following syntactic bindings are exported by (vicare).

Type Annotation: pair ?car-type ?car-type
Parent Type: <pair>

Describe a pair having car of type ?car-type and cdr of type ?car-type. Both ?car-type and ?cdr-type are nested type annotations.

(is-a? '(1 . 2.3) (pair <fixnum> <flonum>))
⇒ #t
Type Annotation: list ?item-type0 ?item-type
Parent Type: <list>

Describe a proper list holding a fixed number of items of the specified types (in the given order). Every ?item-type is a nested type annotation.

(is-a? '(1 2.3) (list <fixnum> <flonum>))
⇒ #t
Type Annotation: vector ?item-type0 ?item-type
Parent Type: <vector>

Describe a vector holding a fixed number of items of the specified types (in the given order). Every ?item-type is a nested type annotation.

(is-a? '#(1 2.3) (vector <fixnum> <flonum>))
⇒ #t
Type Annotation: pair-of ?item-type
Parent Type: <pair>

Describe a pair having both the car and cdr of type ?item-type. The syntax ?item-type is a nested type annotation.

(is-a? '(1 . 2) (pair-of <fixnum>))
⇒ #t
Type Annotation: list-of ?item-type
Parent Type: <list>

Describe a proper list holding any number of items (including zero) all of the specified type. The syntax ?item-type is a nested type annotation.

(is-a? '(1 2) (list-of <fixnum>))       ⇒ #t
(is-a? '()    (list-of <fixnum>))       ⇒ #t
Type Annotation: nelist-of ?item-type
Parent Type: <pair>

Describe a proper non–empty list holding any number of items all of the specified type. The syntax ?item-type is a nested type annotation. This type annotation is expanded to:

(pair ?item-type (list-of ?item-type))
Type Annotation: vector-of ?item-type
Parent Type: <vector>

Describe a vector holding any number of items (including zero) all of the specified type. The syntax ?item-type is a nested type annotation.

(is-a? '#(1 2) (vector-of <fixnum>))    ⇒ #t
(is-a? '#()    (vector-of <fixnum>))    ⇒ #t
Type Annotation: nevector-of ?item-type
Parent Type: <nevector>

Describe a vector holding one or more items all of the specified type. The syntax ?item-type is a nested type annotation.

(is-a? '#(1 2) (nevector-of <fixnum>))  ⇒ #t
(is-a? '#()    (nevector-of <fixnum>))  ⇒ #f
Type Annotation: hashtable ?key-type ?value-type
Parent Type: <hashtable>

Describe a hashtable having keys of type ?key-type and values of type ?value-type. Both ?key-type and ?value-type are nested type annotations.

Type Annotation: enumeration ?symbol0 ?symbol
Parent Type: <symbol>

Describe an enumeration of symbols; it is used to match a symbol in a specified enumeration set.

(is-a? 'ciao (enumeration hello ciao salut ohayo))
⇒ #t

(is-a? 'blue (enumeration hello ciao salut ohayo))
⇒ #f

As special case, if we define an alias for an enumeration type annotation: we can use such identifier to validate symbols. Example:

(define-type greetings
  (enumeration hello ciao salut ohayo))

(is-a? 'ciao greetings) ⇒ #t
(greetings ciao)        ⇒ ciao
(greetings blue)        error→ symbol not in enumeration

The enumeration identifier is indeed used in the implementation of the define-enumeration built–in syntax; (vicare-scheme)define-enumeration.

(define-enumeration greetings
  (hello ciao salut ohayo)
  make-greetings)

(is-a? 'ciao greetings) ⇒ #t
(greetings ciao)        ⇒ ciao
(greetings blue)        error→ symbol not in enumeration
Type Annotation: alist ?key-type ?value-type
Parent Type: <list>

Describe an association list having keys of type ?key-type and values of type ?value-type. Both ?key-type and ?value-type are nested type annotations.

Type Annotation: condition ?cond-type0 ?cond-type
Parent Type: <compound-condition>

Describe a compound condition object holding at least one instance of the specified types (the order does not matter). Every ?cond-type is a nested type annotation that must be one among: <condition>, <compound-condition>, a sub–type of &condition.

(is-a? (condition (make-who-condition 'I)
                  (make-message-condition "hello"))
       (condition &who &message))
⇒ #t

(is-a? (condition (make-who-condition 'I)
                  (make-message-condition "hello"))
       (condition &message &who))
⇒ #t
Type Annotation: lambda ?args-signature => ?rv-signature
Parent Type: <procedure>

Describe a sub–type of <procedure> having a single clause, like procedures defined by lambda. => is the syntactic binding exported by (rnrs base (6)).

The argument ?args-signature must be a syntax object representing the type signature of the procedure’s arguments. The argument ?rv-signature must be a syntax object representing the type signature of the procedure’s return values.

Type Annotation: case-lambda ?clause0 ?clause
Parent Type: <procedure>

Describe a sub–type of <procedure> having multiple clauses, like procedures defined by case-lambda. => is the syntactic binding exported by (rnrs base (6)).

Each ?clause argument must have the format:

(?args-signature => ?rv-signature)

where: ?args-signature must be a syntax object representing the type signature of the clause’s arguments; ?rv-signature must be a syntax object representing the type signature of the clause’s return values.

Type Annotation: or ?type0 ?type
Parent Type: <top>

Describe the union between the specified types. Every ?type is a nested type annotation. A value matches a union of types if its type matches at least one of the union’s types.

(is-a? 1      (or <fixnum> <string>))   ⇒ #t
(is-a? "ciao" (or <fixnum> <string>))   ⇒ #t
(is-a? 1.23   (or <fixnum> <string>))   ⇒ #f
Type Annotation: or ?type0 ?type
Parent Type: <top>

Describe the union between the specified types. Every ?type is a nested type annotation. A value matches a union of types if its type matches at least one of the union’s types.

(is-a? 1      (or <fixnum> <string>))   ⇒ #t
(is-a? "ciao" (or <fixnum> <string>))   ⇒ #t
(is-a? 1.23   (or <fixnum> <string>))   ⇒ #f
Type Annotation: maybe ?type
Parent Type: <top>

It is a shortcut for:

(or <false> ?type)
Type Annotation: not ?type
Parent Type: <top>

Describe the complement of the type. The argument ?type is a nested type annotation. A value of type ?val-type matches the complement of ?type if ?val-type is neither ?type nor a sub–type of ?type.

(is-a? 1   (not <string>))      ⇒ #t
(is-a? 1.0 (not <fixnum>))      ⇒ #f

;;If something is not a "<number>", for sure it is
;;not a "<fixnum>".
(type-annotation-super-and-sub? (not <fixnum>) (not <number>))
⇒ #t
Type Annotation: parent-of ?type
Parent Type: <top>

Describe the parent of the type; an exception is raised if the type has no parent. The argument ?type is a nested type annotation.

(type-annotation=? <struct> (parent-of <record>))
⇒ #t

(type-annotation=? <fixnum> (parent-of <positive-fixnum>))
⇒ #t

(type-annotation=? <positive-fixnum> (parent-of <fixnum>))
⇒ #f
Type Annotation: ancestor-of ?type
Parent Type: <top>

Describe the ancestors of the type; if the type has no parent: the list of ancestors is empty. The argument ?type is a nested type annotation and it is not included in its list of ancestors.

This type annotation can be used to match exactly a type annotation with one of the ancestors of ?type:

(type-annotation-matching (ancestor-of &condition)
                          &condition)
⇒ no-match

(type-annotation-matching (ancestor-of &condition)
                          <condition>)
⇒ exact-match

(type-annotation-matching (ancestor-of &condition)
                          <record>)
⇒ exact-match

(type-annotation-matching (ancestor-of &condition)
                          <struct>)
⇒ exact-match

(type-annotation-matching (ancestor-of &condition)
                          <top>)
⇒ exact-match

(type-annotation-matching <condition>
                          (ancestor-of &condition))
⇒ exact-match

When used along with not, it is used to avoid matching exactly a type annotation with one of the ancestors of ?type:

(type-annotation-matching (not (ancestor-of &condition))
                          <condition>)
⇒ no-match
Type Annotation: type-predicate ?type

A short–cut to specify:

(lambda (?type) => (<boolean>))
Type Annotation: equality-predicate ?type

A short–cut to specify:

(lambda (?type ?type) => (<boolean>))
Type Annotation: comparison-procedure ?type

A short–cut to specify:

(lambda (?type ?type) => (<fixnum>))
Type Annotation: hash-function ?type

A short–cut to specify:

(lambda (?type) => (<non-negative-fixnum>))
Type Annotation: type-of ?expr

Describe the type of ?expr, which must be a Scheme expression. The type signature of ?expr must hold a single value. The expression is expanded and not evaluated; the side effects of the expansion are performed, so this type annotation must be used with care.

(type-annotation-syntax (type-of 123))
⇒ <positive-fixnum>

(type-annotation-syntax (type-of (void)))
⇒ <void>

(let ((fun (lambda () 123)))
  (type-annotation-syntax (type-of (fun))))
⇒ <positive-fixnum>

(type-annotation-syntax (or (type-of 1)
                            (type-of "ciao")
                            (type-of 'hey)))
⇒ (or <positive-fixnum> <string> (enumeration hey))

The expression is not allowed not to return:

(type-annotation-syntax (type-of (error #f "error")))
error→ &assertion

The expression is not allowed to return zero, two or more values:

(type-annotation-syntax (type-of (values)))
error→ &assertion

(type-annotation-syntax (type-of (values 1 2)))
error→ &assertion

(type-annotation-syntax (type-of (values 1 2 3)))
error→ &assertion

The expression is not allowed to return unspecified values:

(letrec ((fun (lambda ({_ . <list>}) (fun))))
  (type-annotation-syntax (type-of (fun))))
error→ &assertion

The expression is expanded in the current lexical environment for phase zero, but with empty lexical environment for the other phases:

(let-syntax ((outer (lambda (stx) 123)))
  (type-annotation-syntax (outer)))
error→ identifier OUTER out of context

(let-syntax  ((outer (lambda (stx) 123)))
  (type-annotation-syntax
     (type-of (let-syntax ((inner (lambda (stx) (outer))))
                (inner)))))
error→ identifier OUTER out of context

Next: , Previous: , Up: annotations   [Contents][Index]