Plait Language
1 Tutorial
1.1 Getting Started
1.2 Simple Data
1.3 Using Built-in Functions
1.4 Conditionals
1.5 Lists
1.6 Definitions
1.7 Datatypes
1.8 Testing and Debugging
1.9 Anonymous Functions
1.10 S-Expressions
1.11 S-Expression Matching
1.12 Tuples and Options
1.13 Programs and Modules
1.14 State
2 Definitions
define
define-values
define-type
define-type-alias
require
trace
module
module+
include
define-syntax-rule
define-syntax
splice
3 Expressions
....
has-type
quote
quasiquote
unquote
unquote-splicing
#%app
lambda
λ
if
cond
case
begin
when
unless
local
letrec
let
let*
shared
parameterize
set!
and
or
list
vector
values
type-case
try
test
test/  exn
time
let/  cc
4 Predefined Functions and Constants
4.1 Booleans
not
4.2 Lists
empty
empty?
cons
cons?
first
rest
second
third
fourth
list-ref
length
append
reverse
member
map
map2
filter
foldl
foldr
build-list
4.3 Numbers
+
-
*
/
modulo
remainder
min
max
floor
ceiling
add1
sub1
=
>
<
>=
<=
zero?
odd?
even?
4.4 Symbols
symbol=?
string->symbol
symbol->string
4.5 Strings
string=?
string-append
string-length
substring
string-ref
to-string
4.6 Characters
char=?
string->list
list->string
4.7 S-Expressions
s-exp-symbol?
s-exp->symbol
symbol->s-exp
s-exp-number?
s-exp->number
number->s-exp
s-exp-string?
s-exp->string
string->s-exp
s-exp-boolean?
s-exp->boolean
boolean->s-exp
s-exp-list?
s-exp->list
list->s-exp
s-exp-match?
4.8 Vector
make-vector
vector-ref
vector-set!
vector-length
4.9 Boxes
box
unbox
set-box!
4.10 Tuples
pair
fst
snd
4.11 Optional Values
none
some
some-v
none?
some?
4.12 Hash Tables
make-hash
hash
hash-ref
hash-set!
hash-remove!
hash-set
hash-remove
hash-keys
4.13 Parameters
make-parameter
parameter-ref
parameter-set!
4.14 Equality
equal?
eq?
4.15 Other Functions
identity
error
display
read
void
print-only-errors
call/  cc
s-exp-content
s-exp
tuple-content
tuple
5 Types
Number
Boolean
Symbol
String
Char
S-Exp
Void
->
Listof
Boxof
Vectorof
Parameterof
Hashof
Optionof
6 Syntactic Literals
typed-in
opaque-type-in
:
7 Type Checking and Inference
8 Untyped, Lazy, and Fuel Modes
8.10

Plait Language

 #lang plait package: plait

The Plait language syntactically resembles the plai language, which is based on racket, but the type system is close to that of ML. For a quick introduction, see the tutorial section or the tutorial videos.

    1 Tutorial

      1.1 Getting Started

      1.2 Simple Data

      1.3 Using Built-in Functions

      1.4 Conditionals

      1.5 Lists

      1.6 Definitions

      1.7 Datatypes

      1.8 Testing and Debugging

      1.9 Anonymous Functions

      1.10 S-Expressions

      1.11 S-Expression Matching

      1.12 Tuples and Options

      1.13 Programs and Modules

      1.14 State

    2 Definitions

    3 Expressions

    4 Predefined Functions and Constants

      4.1 Booleans

      4.2 Lists

      4.3 Numbers

      4.4 Symbols

      4.5 Strings

      4.6 Characters

      4.7 S-Expressions

      4.8 Vector

      4.9 Boxes

      4.10 Tuples

      4.11 Optional Values

      4.12 Hash Tables

      4.13 Parameters

      4.14 Equality

      4.15 Other Functions

    5 Types

    6 Syntactic Literals

    7 Type Checking and Inference

    8 Untyped, Lazy, and Fuel Modes

1 Tutorial

The Plait tutorial videos provide most of the same information as this section.

For a quick refresher of the tutorial content, try "demo.rkt".

    1.1 Getting Started

    1.2 Simple Data

    1.3 Using Built-in Functions

    1.4 Conditionals

    1.5 Lists

    1.6 Definitions

    1.7 Datatypes

    1.8 Testing and Debugging

    1.9 Anonymous Functions

    1.10 S-Expressions

    1.11 S-Expression Matching

    1.12 Tuples and Options

    1.13 Programs and Modules

    1.14 State

1.1 Getting Started

To get started with Plait, download Racket, install it, start DrRacket, and install the plait package using DrRacket’s Install Package... menu item in the File menu.

Then, in the top part of the DrRacket window, type

#lang plait

and click the Run button (or use the keyboard shortcut shown in the Racket menu). In the bottom part of the window, type 1 and hit Return, and you should see this result:

> 1

- Number

1

In other words, the expression 1 has type Number, and the value of the expression is 1.

In this tutorial, we will mostly show expressions as if typed in that bottom area. You can also put the expressions in the top area and hit Run again, but in that case, the type of the result will not print before the result.

In a few places, the tutorial shows lines that include a semicolon, ;. A semicolon starts a comment that continues to the end of the line. For examples of other comment forms, see "demo.rkt".

1.2 Simple Data

Plait supports various kinds of numbers, all with type Number:

> 1

- Number

1

> 0.5

- Number

0.5

> 1/2

- Number

1/2

> 1+2i

- Number

1+2i

The number 1/2 is a literal number, not a division operation. Similarly, 1+2i is a literal complex number. The full syntax of numbers is probably not important, but it’s Racket’s number syntax.

The booleans true and false are written #t and #f, but you can also write them #true and #false:

> #t

- Boolean

#t

> #f

- Boolean

#f

> #true

- Boolean

#t

> #false

- Boolean

#f

Strings are written the usual way with a starting and ending ":

> "apple"

- String

"apple"

> "banana cream pie"

- String

"banana cream pie"

> "yes, \"escape\" quotes with backslash"

- String

"yes, \"escape\" quotes with backslash"

In addition to strings, Plait includes string-like values called symbols. A symbol is written with a single quote ' followed by a sequence of non-whitespace characters.

> 'apple

- Symbol

'apple

> 'banana-cream-pie

- Symbol

'banana-cream-pie

> 'a->b

- Symbol

'a->b

> '#%$^@*&?!

- Symbol

'#%$^@*&?!

Almost any non-whitespace character is allowed in a symbol, except for the following characters:

   ( ) [ ] { } " , ' ` ;

Characters like -, >, and ? are not only allowed in symbols, they are frequently used that way. The | and \ characters are allowed, but they’re treated as quoting and escaping characters, so don’t use them.

Individual characters are infrequently used in Plait, but they’re written with #\:

> #\a

- Char

#\a

> #\b

- Char

#\b

> #\A

- Char

#\A

> #\space ; same as #\ followed by a space

- Char

#\space

1.3 Using Built-in Functions

Plait includes some of the usual functions on numbers, like floor and max. To call a function, start with an open parenthesis, then use the function name, then the argument, and finally a closing parenthesis:

> (floor 1.2)

- Number

1.0

> (max 3 5)

- Number

5

The parenthesis must be before the function, not after. Don’t use commas between arguments. Also, extra parentheses are not allowed. If you include extra parentheses around 3, for example, then Plait will complain that 3 is not a function, since the parentheses mean a function call:

> (max (3) 5)

eval:24:0: typecheck failed: call of a non-function

  possible reason: extra parentheses create a function call

  type mismatch: (-> '_a) vs. Number

  sources:

   3

The same error happens if you add parentheses around the call to max, since the result of max is a number:

> ((max 3 5))

eval:25:0: typecheck failed: call of a non-function

  possible reason: extra parentheses create a function call

  type mismatch: (-> '_a) vs. Number

  sources:

   (max 3 5)

   max

The type of a function is written with -> in parentheses. The function’s argument types appear before the arrow, and the function’s result type is after the arrow. A function is a value, so if you evaluate just max without calling it, then Plait will show the type and print that the result is a procedure (which is synonymous with “function” in Plait):

> max

- (Number Number -> Number)

#<procedure:max>

Unlike most languages, arithmetic operations such as + and * in Plait are just functions, and they are called the same way as other functions—just after an open parenthesis, and grouped with their arguments by a closing parenthesis:

> (+ 3 5)

- Number

8

> (* 3 5)

- Number

15

> +

- (Number Number -> Number)

#<procedure:+>

Note that + is allowed as a function name in fundamentally the same way that + is allowed in the symbol '+.

If you try to put the operator-as-function in the middle of its arguments, Plait will complain that the first argument isn’t a function, because the opening parenthesis means that first thing in the parenthesis should be a function to call:

> (3 + 5)

eval:30:0: typecheck failed: call of a non-function

  possible reason: extra parentheses create a function call

  type mismatch: ((Number Number -> Number) Number -> '_a)

vs. Number

  sources:

   3

If you omit then parentheses, then Plait see three separate expressions:

> + 3 5
- (Number Number -> Number)
#<procedure:+>
- Number
3
- Number
5

The style of syntax that puts a function/operation name up front and grouped with its arguments in parentheses is called parenthesized prefix notation.

Treating + like any other function makes Plait simpler, as does using parenthesized prefix notation. Since you didn’t have to create Plait, you may not care that Plait is simpler this way. But if you’re building your own interpreter in a class that’s about programming languages, then Plait’s regularity turns out to be a convenient design to imitate; you can spend more time studying the meaning of programming constructs and less time worrying about the syntax of those constructs.

Here are some example uses of other built-in functions, and you can click on any of the function names her eto jump to the documentation:

> (not #t)

- Boolean

#f

> (not #f)

- Boolean

#t

> (+ 1 2)

- Number

3

> (- 1 2)

- Number

-1

> (* 1 2)

- Number

2

> (< 1 2)

- Boolean

#t

> (> 1 2)

- Boolean

#f

> (= 1 2)

- Boolean

#f

> (<= 1 2)

- Boolean

#t

> (>= 1 2)

- Boolean

#f

> (string-append "a" "b")

- String

"ab"

> (string=? "a" "b")

- Boolean

#f

> (string-ref "a" 0)

- Char

#\a

> (string=? "apple" (string-append "a" "pple"))

- Boolean

#t

> (equal? "apple" (string-append "a" "pple"))

- Boolean

#t

> (eq? 'apple 'apple)

- Boolean

#t

> (eq? 'apple 'orange)

- Boolean

#f

Note that some operations work on multiple types. For example, equal? works on any two values, as long as the two values have the same type. That flexibility and constraint is reflected in the type of equal? by a symbol placeholder 'a, which you can read as “a type to be picked later.” A specific type is picked for every individual use of equal?:

> (equal? 1 1)

- Boolean

#t

> (equal? "one" "one")

- Boolean

#t

> equal?

- ('a 'a -> Boolean)

#<procedure:equal?>

> (equal? 1 "one")

eval:51:0: typecheck failed: Number vs. String

  sources:

   equal?

   1

   "one"

1.4 Conditionals

The if form works in the usual way, and it follows the parenthesized-prefix convention of being grouped with its subexpressions with parentheses:

> (if (equal? "apple" "banana")
      'yes
      'no)

- Symbol

'no

The line breaks above don’t matter to Plait, but readers of your programs will appreciate it if you normally put the “then” and “else” branches on their own lines and correctly intent them. The correct indentation is the indentation that DrRacket gives you automatically when you hit Return after (equal? "apple" "banana"). If you ever need to reindent a region of code, you can select the region and hit Tab.

The cond form is a multi-way if. A cond form has a sequence of clauses, where each clause has a “question” and a result expression. The result expression is used only when the question produces true. The cond form tries the clauses in order, and as soon as it finds a true result from a question, it produces the corresponding result. The last clause’s question cal be else as a synonym for #t.

> (cond
    [(< 2 1) 17]
    [(> 2 1) 18])

- Number

18

> (cond
    [(< 2 1) (/ 1 0)] ; result expression skipped
    [(> 2 1) 18])

- Number

18

> (cond
    [#t 8]
    [#t (/ 1 0)]) ; second clause not reached

- Number

8

> (cond
    [(< 3 1) 0]
    [(< 3 2) 1]
    [(< 3 3) 2]
    [(< 3 4) 3])

- Number

3

> (cond
    [(eq? 'a 'b) 0]
    [(eq? 'a 'c) 1]
    [else 2])

- Number

2

Plait doesn’t distinguish between square brackets [ and ] and parentheses ( and ), as long as each opener and closer match. You could use parentheses instead of square brackets in the above examples—but don’t. Plait programmers should use square brackets in specific places by convention to make programs more readable. Follow the conventions that you see in this tutorial.

The and and or forms are short-cicuiting, too, and they work with any number of boolean subexpressions:

> (and #t #t)

- Boolean

#t

> (and #t #f)

- Boolean

#f

> (and (< 2 1) #t)

- Boolean

#f

> (and (< 2 1) (zero? (/ 1 0))) ; second expression is not evaluated

- Boolean

#f

> (or #f #t)

- Boolean

#t

> (or #f #f)

- Boolean

#f

> (or (< 1 2) (zero? (/ 1 0))) ; second expression is not evaluated

- Boolean

#t

> (and #t #t #t #t)

- Boolean

#t

> (or #f #f #f)

- Boolean

#f

1.5 Lists

Plait lists are uniform, meaning that all of the elements of a list must have the same type. The list form creates a list:

> (list 1 2 (+ 3 4))

- (Listof Number)

'(1 2 7)

> (list (string-append "a" "b") "c")

- (Listof String)

'("ab" "c")

As you can see, the type of a list is written with Listof and then the type of the elements of the list. You also see that the result is printed using '. You can use a ' to create a list, but only for literal-value content (i.e., no subexpressions to evaluate):

> '(1 2 7)

- (Listof Number)

'(1 2 7)

> '(1 2 (+ 3 4))

eval:70:0: typecheck failed: Symbol vs. Number

  sources:

   (+ 3 4)

   3

   +

To understand that last error message, start by observing that the ' for a literal list is the same as a the ' for a symbol. As it turns out, a ' for a list implicitly distributes the ' to each element of the list. So, '(a b) is equivalent to (list 'a 'b). It’s also the case that '(1 2 7) is equivalent to (list '1 '2 '7), because ' has no effect on a number, boolean, or string:

> '1

- Number

1

> '#t

- Boolean

#t

> '"apple"

- String

"apple"

> '(milk cookies)

- (Listof Symbol)

'(milk cookies)

> '((pen paper) (rock scissors paper))

- (Listof (Listof Symbol))

'((pen paper) (rock scissors paper))

The expression '(1 2 (+ 3 4)) fails because that’s the same as (list 1 2 '(+ 3 4)), and '(+ 3 4) fails because it’s the same as (list '+ 3 4), but a list cannot mix a symbol with numbers.

A list is immutable. That is, the value '(1 2 3) is as unchanging as the numbers 1, 2, and 3 within the list. You can’t change a list to add new elements to it—but you can create a new list that is like the old one, except that it has another element. The cons function takes an element and a list and “adds” the element to the front of the list, creating a new list with all of the elements:

> (cons 1 '(2 3))

- (Listof Number)

'(1 2 3)

> (cons "apple" '("banana"))

- (Listof String)

'("apple" "banana")

The cons operation is constant-time, because a list is internally represented as a singly linked list, and cons simply creates a new cell that contains the new value and then points to the existing list.

If you have two lists, instead of one element and a list, you can combine the lists with append:

> (append '(1 2) '(3 4))

- (Listof Number)

'(1 2 3 4)

Don’t confuse cons and append. The cons function takes an element and a list, while append takes a list and a list. That difference is reflected in their types:

> cons

- ('a (Listof 'a) -> (Listof 'a))

#<procedure:cons>

> append

- ((Listof 'a) (Listof 'a) -> (Listof 'a))

#<procedure:append>

Mixing them up will trigger a type error:

> (cons '(1) '(2 3))

eval:81:0: typecheck failed: (Listof Number) vs. Number

  sources:

   cons

   2

   (quote (2 3))

   (quote (1))

> (append 1 '(2 3))

eval:82:0: typecheck failed: (Listof '_a) vs. Number

  sources:

   append

   1

A list doesn’t have to contain any values:

> (list)

- (Listof '_a)

'()

The empty list is so useful that it has a name: empty. Although the list form may seem fundamental, the true list-construction primitives are empty and cons, and you can build up any other list using those:

> empty

- (Listof 'a)

'()

> (cons "food" empty)

- (Listof String)

'("food")

> (cons "dog" (cons "food" empty))

- (Listof String)

'("dog" "food")

The empty? function determines whether a list is empty, and cons? determines whether a list has at least one item:

> (empty? empty)

- Boolean

#t

> (empty? '())

- Boolean

#t

> (cons? (cons 1 '()))

- Boolean

#t

> (cons? '(1))

- Boolean

#t

> (cons? empty)

- Boolean

#f

> (empty? '(1))

- Boolean

#f

The cons operation constructs a new value from two pieces. The first and rest operations are the opposite of cons. Given a value produced by cons, first returns the item that cons added to the start of the list, and rest returns the list that cons added to. More generally, first gets the first item from a list, and rest gets everything list in the list when the first argument is removed.

> (first (cons 1 '(2 3)))

- Number

1

> (rest (cons 1 '(2 3)))

- (Listof Number)

'(2 3)

> (first '("apple" "banana" "coconut"))

- String

"apple"

> (rest '("apple" "banana" "coconut"))

- (Listof String)

'("banana" "coconut")

> (first (rest '("apple" "banana" "coconut")))

- String

"banana"

> (rest (rest '("apple" "banana" "coconut")))

- (Listof String)

'("coconut")

Plait also provides second, third, fourth, and list-ref. Those functions are sometimes useful to extract pieces of a list that has a known shape. Functions that take the first of a list and recur with the rest turn out to be be more common. Here’s a function that check whether "milk" is in a list of strings:

> (define (got-milk? [items : (Listof String)])
    (cond
      [(empty? items) #f]
      [(cons? items) (or (string=? (first items) "milk")
                         (got-milk? (rest items)))]))
> (got-milk? empty)

- Boolean

#f

> (got-milk? '("milk" "cookies"))

- Boolean

#t

> (got-milk? '("cookies" "milk"))

- Boolean

#t

> (got-milk? '("cookies" "cream"))

- Boolean

#f

1.6 Definitions

The define form defines an identifier to be a synonym for a value:

> (define pi 3.14)
> pi

- Number

3.14

> (define tau (+ pi pi))
> tau

- Number

6.28

The define form can also define a function. The difference is that define for a function definition is followed by an open parenthesis, then the function name, a name for each argument, and a closing parenthesis. The expression afterward is the body of the function, which can refer to the function arguments and is evaluated when the function is called.

> (define (circle-area r)
    (* pi (* r r)))
> (circle-area 10)

- Number

314.0

Since Getting Started, we have been evaluating forms only in DrRacket’s bottom area, which is also known as the interactions area. Definitions normally go in the top area—which is known as the definitions area, naturally.

Put these two definitions in the definitions area:

(define (is-odd? x)
  (if (zero? x)
      #f
      (is-even? (- x 1))))
 
(define (is-even? x)
  (if (zero? x)
      #t
      (is-odd? (- x 1))))

Click Run. The functions is-odd? and is-even? are now available in the interactions area:

> is-odd?

- (Number -> Boolean)

#<procedure:is-odd?>

> (is-odd? 12)

- Boolean

#f

In our definitions of pi and tau, plait inferred that the newly defined names have type Number and that is-odd? has type (Number -> Boolean). Programs are often easier to read and understand if you write explicitly the type that would otherwise be inferred. Declaring types can sometimes help improve or localize error messages when Plait’s attempt to infer a type fails, since inference can other end up depending on the whole program.

Declare a type for a constant by writing : followed by a type after the defined identifier:

(define groceries : (Listof String) '("milk" "cookies"))

Alternatively, you can declare an idenitifier’s type separate from its definition by using :.

(groceries : (Listof String))
(define groceries '("milk" "cookies"))

The declaration can appear before or after the definition, as long as it is in the same layer of declarations as the definition. You can even have multiple type definitions for the same identifier, and the type checker will ensure that they’re all consistent.

For a function, attach a type to an argument by writing square brackets around the argument name, :, and a type. Write the function’s result type with : and the type after the parentheses that group the function name with its arguments.

(define (starts-milk? [items : (Listof String)]) : Boolean
  (equal? (first items) "milk"))

Or, of course, declare the type separately:

(starts-milk? : ((Listof String) -> Boolean))
(define (starts-milk? items)
  (equal? (first items) "milk"))

You can declare local functions and constants by using the local form as a wrapper. The definitions that appear after local are visible only within the local form, and the result of the local form is the value of the expression that appears after the definitions. The definitions must be grouped with square brackets.

> (local [(define pi-ish 3)
          (define (approx-circle-area r)
            (* pi-ish (* r r)))]
     (approx-circle-area 2))

- Number

12

> pi-ish ; not visible outside the local

eval:123:0: code:line: free variable while typechecking

  in: code:line

> approx-circle-area ; not visible outside the local

eval:124:0: code:line: free variable while typechecking

  in: code:line

The local form is most often used inside a function to define a helper function or to avoid a repeated computating involving the function arguments.

> (define (discard-first-if-fruit items)
    (local [(define a (first items))]
      (cond
       [(equal? a "apple") (rest items)]
       [(equal? a "banana") (rest items)]
       [else items])))
> (discard-first-if-fruit '("apple" "potato"))

- (Listof String)

'("potato")

> (discard-first-if-fruit '("banana" "potato"))

- (Listof String)

'("potato")

> (discard-first-if-fruit '("potato" "apple"))

- (Listof String)

'("potato" "apple")

The let and letrec forms are similar to local, but they are somewhat more compact by avoiding the requirement to write define. The discard-first-if-fruit example above can be equivalently written using let:

(define (discard-first-if-fruit items)
  (let ([a (first items)])
    (cond
     [(equal? a "apple") (rest items)]
     [(equal? a "banana") (rest items)]
     [else items])))

1.7 Datatypes

So far, we have only seen built-in types like Number and (Listof String). Sometimes, it’s useful to define your own name as a shorthand for a type, such as defining Groceries to be equivalent to (Listof String):

(define-type-alias Groceries (Listof String))
(define shopping-list : Groceries '("milk" "cookies"))

Note that, by convention, all type names are capitalized. Plait is case-sensitive.

But what if the data that you need to represent is not easily encoded in existing types, such as when you need to keep track of a tiger’s color and stripe count (which doesn’t work as a list, since a list can’t have a number and a string)? And what if your type, say Animal, has values of different shapes: tigers that have color and stripe counts, plus snakes that have a color, weight, and favorite food?

The define-type form handles those generalizations. The general form is

(define-type Type
  (variant-name_1 [field-name_1 : Type_1]
                  [field-name_2 : Type_2]
                  ...)
  (variant-name_2 [field-name_3 : Type_3]
                  [field-name_4 : Type_4]
                  ...)
  ...)

with any number of variants and where each variant has any number of typed fields. If you’re used to Java-style classes, you can think of Type as an interface, and each variant is a class that implements the interface. Unlike Java classes, a variant name doesn’t work as a type name; it only works to create an instance of the variant.

For example, the following definition is suitable for representing animals that can be either tigers or snakes:

(define-type Animal
  (tiger [color : Symbol]
         [stripe-count : Number])
  (snake [color : Symbol]
         [weight : Number]
         [food : String]))

After this definition, Animal can be used as a type, while tiger and snake work as functions to create Animals:

> (tiger 'orange 12)

- Animal

(tiger 'orange 12)

> (snake 'green 10 "rats")

- Animal

(snake 'green 10 "rats")

The definition of Animal creates several additional functions:

The name tiger? was formed by adding a ? to the end of the variant name tiger, tiger-color is formed by adding a - between the variant name and field name, and so on.

> (define tony (tiger 'orange 12))
> (define slimey (snake 'green 10 "rats"))
> (tiger? tony)

- Boolean

#t

> (tiger? slimey)

- Boolean

#f

> (tiger-color tony)

- Symbol

'orange

> (snake-food slimey)

- String

"rats"

> (tiger-color slimey)

- Symbol

tiger-color: contract violation

  expected: tiger?

  given: (snake 'green 10 "rats")

  in: the 1st argument of

      (->

       tiger?

       (or/c

        undefined?

        ...pkgs/plait/main.rkt:1013:41))

  contract from: tiger-color

  blaming: use

   (assuming the contract is correct)

  at: eval:132:0

Note that the type of (tiger-color slimey) printed before an error was reported. That’s because (tiger-color slimey) is well-typed as far as Plait can tell, since tiger-color wants an Animal and slimey has type Animal. We’ll see that type-case provides an alterntive to selectors like tiger-color that is less dangerous than the selector.

Using Animal as a type and the tiger? and snake? predicates, we can write a function that extracts the color of any animal:

> (define (animal-color [a : Animal]) : Symbol
    (cond
      [(tiger? a) (tiger-color a)]
      [(snake? a) (snake-color a)]))
> (animal-color tony)

- Symbol

'orange

> (animal-color slimey)

- Symbol

'green

When writing animal-color, what if we forget the snake? case? What if we get snake-color and tiger-color backwards? Unfortunately, the type checker cannot help us detect those problems. If we use type-case, however, the type checker can help more.

The general form of a type-case expresison is

(type-case Type value-expression
  [(variant-name_1 field-var_1 field-var_2 ...)
   result-expression_1]
  [(variant-name_2 field-var_3 field-var_4 ...)
   result-expression_2]
  ...)

The value-expression must produce a value matching Type. Every variant of Type must be represented by a clause with a matching variant-name. For that clause, the number of field-vars must match the declared number of fields for the variant. The type checker can check all of those requirements.

To produce a value, type-case determines the variant that is instanited by the result of value-expression. For the clause matching that variant (by name), type-case makes each field-var stand for the corresponding field (by position) within the value, and then evaluates the corresponding result-expression. Here’s animal-color rewritten with type-case:

> (define (animal-color [a : Animal]) : Symbol
    (type-case Animal a
      [(tiger col sc) col]
      [(snake col wgt f) col]))
> (animal-color tony)

- Symbol

'orange

> (animal-color slimey)

- Symbol

'green

Put the definitions of Anmal and animal-color in DrRacket’s definitions area. Then, you can mouse over a in animal-color to confirm that it means the a that is passed as an argument. Mouse over col to see that it means one of the variant-specific fields. Try changing the body of animal-color to leave out a clause or a field variable and see what error is reported when you hit Run.

You should think of type-case as a pattern-matching form. It matches a value like (tiger 'orange 12) to the pattern (tiger col sc) so that col stands for 'orange and sc stands for 12. A value like (snake 'green 10 "rats") does not match the pattern (tiger col sc), but it matches the pattern (snake col wgt f).

At the end of Lists, we saw a got-milk? function that uses cond, similar to the way the dangerous version of animal-color uses cond. The type-case form works on list types with empty and (cons fst rst) patterns, so here’s an improved got-milk?:

> (define (got-milk? [items : (Listof String)])
    (type-case (Listof String) items
      [empty #f]
      [(cons item rst-items) (or (string=? item "milk")
                                 (got-milk? rst-items))]))
> (got-milk? empty)

- Boolean

#f

> (got-milk? '("cookies" "milk"))

- Boolean

#t

Note that there are no parentheses around empty in got-milk?. That’s because empty is never called as a constructor function—it’s simply a constant value—so the pattern form doesn’t have parentheses, either. The empty pattern is a special case in type-case; all other variant names in a type-case form will have parentheses, since they will always be used a constrcutor functions, even if the variant has no fields.

> (define-type Grade
    (letter [alpha : Symbol])
    (pass-fail [pass? : Boolean])
    (incomplete))
> (letter 'A)

- Grade

(letter 'A)

> (pass-fail #t)

- Grade

(pass-fail #t)

> (incomplete)

- Grade

(incomplete)

> (define (passed-course? [g : Grade]) : Boolean
    (type-case Grade g
      [(letter a) (not (eq? a 'F))]
      [(pass-fail p?) p?]
      [(incomplete) #f]))
> (passed-course? (letter 'B))

- Boolean

#t

> (passed-course? (incomplete))

- Boolean

#f

You can also use else for a final clause in type-case to catch any variants that are not already covered.

> (define (high-pass? [g : Grade]) : Boolean
    (type-case Grade g
      [(letter a) (eq? a 'A)]
      [else #f]))
> (high-pass? (letter 'A))

- Boolean

#t

> (high-pass? (incomplete))

- Boolean

#f

When you use else, however, the type checker is less helpful for making sure that you’ve considered all cases.

1.8 Testing and Debugging

Plait includes built-in support for testing your programs. The test form takes two expressions and makes sure that they produce the same value. Typically, the first expression is a function call, and the second expression is the expected result of the function. The test form prints output that starts “good” if the test passes or “bad” if it fails.

> (define (taste s)
    (cond
      [(equal? s "milk") 'good]
      [else 'not-as-good]))
> (test (taste "milk") 'good)

- Void

good (taste "milk") at line 162

  expected: 'good

  given: 'good

> (test (taste "brussel sprouts") 'not-as-good)

- Void

good (taste "brussel sprouts") at line 163

  expected: 'not-as-good

  given: 'not-as-good

> (test (taste "beets") 'bad)

- Void

bad (taste "beets") at line 164

  expected: 'bad

  given: 'not-as-good

They say that no news is good news. To suppress the output for passing tests, so that only failing test strigger output, use (print-only-errors #t).

> (print-only-errors #t)

- Void

> (test (taste "kale") 'not-as-good)

- Void

> (test (taste "anchovies") 'bad)

- Void

bad (taste "anchovies") at line 167

  expected: 'bad

  given: 'not-as-good

To test that an expression reports an expected error, use test/exn. The test/exn form’s section expression should produce a string, and test/exn checks that an error is reported where the string occurs in the error message. You can only test for errors that your program specifically reports using the error function.

> (define (always-fail [n : Number]) : Number
    (error 'always-fail "we're not actually returning a number"))
> (test/exn (always-fail 42) "not actually")

- Void

> (test/exn (always-fail 42) "should not get called")

- Void

bad (always-fail 42) at line 170

  expected: "should not get called"

  given: "always-fail: we're not actually returning a number"

When you write a program (in the definitions area of DrRacket), the order of function definitions generally does not matter, even if the functions call each other. A test at the top level of a program, however, must appear after all functions that the test may end up calling. To relax this constraint, wrap tests in a (module+ test ....) form. A (module+ test ....) wrapper effectively moves its content to the end of the program.

(module+ test
  (test (retaste "milk") '(still good)))
 
(define (retaste s)
  (list 'still (taste s)))

A good set of tests will cause all expressions in a program to be evaluated at least once. DrRacket can help you check that your program has good test coverage. In DrRacket’s Language menu, select Choose Language, click Show Details, click Submodules to run, and then select the Syntactic test suite coverage option. After selecting that option, when you Run a program, it will stay its normal color if all is well. If some expression has not been covered, however, the program text will go mostly black, and any expression that has not been evaluated will turn orange with a black background. Resolve the problem and restore your program text’s color by adding more tests.

When you’re debugging a program, it may be helpful to see the arguments that are passed to a particular function and the results that the function returns. You can enable that kind of tracing for a function with the trace declaration, which must appear after the function’s definitions.

(define (got-milk? [items : (Listof String)])
  (type-case (Listof String) items
    [empty #f]
    [(cons item rst-items) (or (string=? item "milk")
                               (got-milk? rst-items))]))
(trace got-milk?)
> (got-milk? empty)

- Boolean

>(got-milk? '())

<#f

#f

> (got-milk? '("cookies" "milk"))

- Boolean

>(got-milk? '("cookies" "milk"))

>(got-milk? '("milk"))

<#t

#t

As you’re devloping a program, sometimes it’s useful to run a partial program where you haven’t yet decided on part of the implementation. The .... expression (with four dots) can be used in place of any expression of any type. A program using .... can compile and run, but the .... reports an error if it is reached during evaluation.

> (define (got-milk? [items : (Listof String)])
    (type-case (Listof String) items
      [empty #f]
      [(cons item rst-items) ....]))

- Void

> (got-milk? '())

- Boolean

#f

> (got-milk? '("cheese"))

- Boolean

reached a `....` placeholder

1.9 Anonymous Functions

After we define a function, the name of the function can be used as a value without calling it. If you just evaluate the function name, then Plait will print something like #<procedure>.

> (define (plus-five n)
    (+ n 5))
> plus-five

- (Number -> Number)

#<procedure:plus-five>

More usefully, you might pass the function to another function that calls it. For example, the map function takes a function and a list, and it applies the function to each element of the list to produce a new list.

> (map plus-five
       '(1 2 3))

- (Listof Number)

'(6 7 8)

Sometimes, and especially with map, you need a one-off function that doesn’t need to be defined for everyone else to see, and it doesn’t even need a name. You can make an anonymous function by using lambda:

> (map (lambda (n)
         (+ n 6))
       '(1 2 3))

- (Listof Number)

'(7 8 9)

The form (lambda (n) (+ n 6)) means “the function that takes an argument n and returns (+ n 6).” You can evaluate a lambda form without passing it anywhere, although that isn’t particularly useful:

> (lambda (n)
    (+ n 7))

- (Number -> Number)

#<procedure>

Notice that the result has a function type: it’s a function that takes a Number and returns a Number.

An anonymous function created with lambda doesn’t have to stay anonymous. Since you can use a lambda form anywhere that an expression is allowed, you can use in define:

(define plus-eight : (Number -> Number)
  (lambda (n)
    (+ n 8)))

This definition is completely equivalent to the function-definition shorthand:

(define (plus-eight [n : Number]) : Number
  (+ n 8))

Another interesting property of lambda functions is that, just like any local function, the body of a lambda can see any surrounding variable binding. For example, the lambda body in the following add-to-each function can see the m that is passed to add-to-each:

> (define (add-to-each m items)
    (map (lambda (n)
           (+ n m))
         items))
> (add-to-each 7 '(1 2 3))

- (Listof Number)

'(8 9 10)

> (add-to-each 70 '(1 2 3))

- (Listof Number)

'(71 72 73)

You can declare types for lambda arguments and results similar to declaring them with define in the function-definition shorthand:

(lambda ([s : String]) : Boolean
  (> (string-length s) 10))

- (String -> Boolean)

#<procedure>

1.10 S-Expressions

If we write (+ pi pi), then given our earlier definition of pi, the result is as you’d expect:

> (+ pi pi)

- Number

6.28

We could add a ' to the front of that expression and get a completely different result—a list of symbols:

> '(+ pi pi)

- (Listof Symbol)

'(+ pi pi)

If you’re studying programming languages and building interpreters, this looks like a handy coincidence. You can represent an expression as a list! Unfortunately, this trick does not always work:

> '(+ 1 2)

eval:192:0: typecheck failed: Symbol vs. Number

  sources:

   (quote (+ 1 2))

   +

   1

A list cannot contain a mixture of numbers and symbols, so it cannot directly represent the expression (+ 1 2).

If you’ve had some experience programming in Java, you might think that the solution is a list of Objects, because anything can be coerced to and from the type Object. That is, we would be able to mix a symbol as Object with two numbers as Objects.

Plait doesn’t have an Object type, but it does have an S-Exp type, which is similar. Even better, the S-Exp type works with a convenient '-like shortcut. The S-Exp shortcut is ` (usually pronounced “backquote”) instead of ':

> `(+ 1 2)

- S-Exp

`(+ 1 2)

When an S-expression is list-like, then you can corece the S-expression to a list using s-exp->list. The result is a list of S-Exps:

> (s-exp->list `(+ 1 2))

- (Listof S-Exp)

(list `+ `1 `2)

If an S-expression isn’t list-like, the coercion fails. Other coercions include s-exp->number and s-exp->symbol. You can go the other way with number->s-exp, symbol->s-exp, and list->s-exp. Functions like s-exp-list? and s-exp-number? report whether an S-expression is list-like or number-like.

> `1

- S-Exp

`1

> (s-exp->list `1)

- (Listof S-Exp)

s-exp->list: not a list: `1

> (s-exp->number `1)

- Number

1

> (number->s-exp 1)

- S-Exp

`1

> (list->s-exp (list (symbol->s-exp '+)
                     (number->s-exp 1)
                     (number->s-exp 2)))

- S-Exp

`(+ 1 2)

> (s-exp-number? `1)

- Boolean

#t

> (s-exp-list? `1)

- Boolean

#f

The backquote ` versus forward quote ' distinction is subtle. A convention to help highlight the difference is to mostly use curly braces with `. Curly braces are interchangable with parentheses and square brackets, and Plait won’t print results with curly braces, but the visual cue can still help when reading programs.

> `{+ 1 2}

- S-Exp

`(+ 1 2)

> `{* 3 {+ 4 x}}

- S-Exp

`(* 3 (+ 4 x))

The S-expression ` has an extra feature that the list-constructing ' lacks: a way to escape back to the evaluated-expression world by using , (i.e., a comma). The escaped expression must produce a S-expression, and the result S-expression takes the place of the escape:

> `{+ 1 ,(number->s-exp (+ 3 4))}

- S-Exp

`(+ 1 7)

The ,@ escape form is similar to ,, but ,@ is a splicing escape that expects a list of S-expressions and inlines the elements into the enclosing list-like S-expression.

> `{+ ,@(list (number->s-exp 1) (number->s-exp (+ 3 4)))}

- S-Exp

`(+ 1 7)

> `{+ ,(list->s-exp (list (number->s-exp 1) (number->s-exp (+ 3 4))))}

- S-Exp

`(+ (1 7))

1.11 S-Expression Matching

Since the equal? function works on any kind of value, it can compare two S-expressions to determine whether they are the same:

> (equal? `{+ 1 2} `{+ 1 2})

- Boolean

#t

> (equal? `{+ 1 2} `{+ 1 4})

- Boolean

#f

Suppose that you don’t just want to recognize `{+ 1 2}, but you want to recognize any list-like S-expression that has three elements where the first element is '+-like and the other two elements are number-like. That recognition problem is tedious to implement, due to the many required many checks and coercions.

> (define (is-plus-numbers? se)
    (and (s-exp-list? se)
         (let ([l (s-exp->list se)])
           (and (= 3 (length l))
                (let ([a (first l)])
                  (and (s-exp-symbol? a)
                       (eq? '+ (s-exp->symbol a))))
                (s-exp-number? (second l))
                (s-exp-number? (third l))))))
> (is-plus-numbers? `{+ 1 2})

- Boolean

#t

> (is-plus-numbers? `1)

- Boolean

#f

> (is-plus-numbers? `{+ 3 y})

- Boolean

#f

> (is-plus-numbers? `{{+} 1 2})

- Boolean

#f

The s-exp-match? function simplifies recognition tasks for S-expressions. It’s like equal? on S-expressions, but the first S-expression can have special symbols that match different classes of values, instead of matching themselves literally. The special symbols include NUMBER, which matchs any number, so is-plus-numbers? is more simply implemented like this:

> (define (is-plus-numbers? se)
    (s-exp-match? `{+ NUMBER NUMBER} se))
> (is-plus-numbers? `{+ 1 2})

- Boolean

#t

> (is-plus-numbers? `{+ 3 y})

- Boolean

#f

Other special symbols include SYMBOL, which matches any symbol, and ANY, which matches anything.

> (define (single-argument-lambda? se)
    (s-exp-match? `{lambda {SYMBOL} ANY} se))
> (single-argument-lambda? `{lambda {x} {+ x 1}})

- Boolean

#t

> (single-argument-lambda? `{lambada 0})

- Boolean

#f

The symbol ... is even more special. It causes the preceeding S-expression to match zero or more times to cover multiple elements in an enclosing list. For example, `{SYMBOL ...} would match a list-like S-expression that has any number of symbol-like elements.

> (define (any-argument-lambda? se)
    (s-exp-match? `{lambda {SYMBOL ...} ANY} se))
> (any-argument-lambda? `{lambda {x} {+ x 1}})

- Boolean

#t

> (any-argument-lambda? `{lambda {x y z} {+ x 1}})

- Boolean

#t

> (any-argument-lambda? `{lambda {} {+ x 1}})

- Boolean

#t

> (any-argument-lambda? `{lambada 0})

- Boolean

#f

1.12 Tuples and Options

If you want to combine a small number of values in a single value, and if the values have different types (so that a list doesn’t work), you can use a tuple as an alternative to creating a new datatype with a single variant.

The values form creates a tuple from any number of values. The type of a tuple reveals the type of every component value in the tuple, separating the types with *.

> (values 1 "milk" 'apple)

- (Number * String * Symbol)

(values 1 "milk" 'apple)

> (values '(1 2 3) #f)

- ((Listof Number) * Boolean)

(values '(1 2 3) #f)

Using values, this consume function can effectively return two values each time that it is called:

(define (consume [s : String]) : (Symbol * String)
  (cond
   [(equal? s "milk") (values 'drink "Mmm....")]
   [(equal? s "beets") (values 'eat "Ugh....")]
   [else (values 'sleep "Zzz...")]))

To extract the component values from a tuple, match the tuple with names using define-values.

> (consume "milk")

- (Symbol * String)

(values 'drink "Mmm....")

> (define-values (action response) (consume "beets"))
> action

- Symbol

'eat

> response

- String

"Ugh...."

The convenience functions fst and snd can be used in the special case of a 2-value tuple to extract the first or second component.

> (snd (consume "milk"))

- String

"Mmm...."

Sometimes, instead of always returning multiple values, you’ll want a function that returns either one value or no value. A tuple is no help for that case, but Plait predefines a helpful datatype called Optionof:

(define-type (Optionof 'a)
  (none)
  (some [v : 'a]))

The 'a in this definition of Optionof indicates that you can return any kind of value in a some.

> (define (get-slogan [s : String]) : (Optionof String)
    (cond
     [(equal? s "milk") (some "It does a body good")]
     [else (none)]))
> (get-slogan "milk")

- (Optionof String)

(some "It does a body good")

> (get-slogan "iced tea")

- (Optionof String)

(none)

> (type-case (Optionof String) (get-slogan "moon pie")
    [(some s) s]
    [(none) "no comment"])

- String

"no comment"

1.13 Programs and Modules

When you write a program using #lang plait, you are technically defining a module. A Plait module contains a mixture of expressions and definitions. The expressions are evaluated in order, and the value of each expression is printed after the expression is evaluated (unless the result value has type Void). The order of function definitions doesn’t matter, as long as a function definition appears before any expression that eventually calls the function.

#lang plait
 
(define (is-odd? x)
  (if (zero? x)
      #f
      (is-even? (- x 1))))
 
(is-odd? 0) ; ok
#;(is-odd? 1) ; won't work, because it needs is-even?
 
(define (is-even? x)
  (if (zero? x)
      #t
      (is-odd? (- x 1))))
 
(is-even? 1) ; ok
(is-odd? 1) ; ok

Note the use of #; in the example above. A #; comments out the entire form that follows it, which is handy for commenting out a definition of expression, even when the definition or expression spans multiple lines.

Modules written with the module form can be nested in other modules. A nested module is called a submodule. Plait programs don’t often use submodules that are written with module, but the module+ form is more common. A module+ form creates a submodule by merging all module+s that use the same name. A typical use of module+ is to move all of a program’s tests into a test submodule.

#lang plait
 
(define (is-odd? x)
  (if (zero? x)
      #f
      (is-even? (- x 1))))
 
(module+ test
  (is-odd? 0)
  (is-odd? 1))
 
(define (is-even? x)
  (if (zero? x)
      #t
      (is-odd? (- x 1))))
 
(module+ test
  (is-even? 1)
  (is-odd? 1))

The submodule name test is special, because DrRacket automatically runs a test submodule (if one is present) after running the enclosing module. In the above example, since the test submodule is run after the encloding module that defines is-odd? and is-even?, the tests can use all of the functions. Another advantage of putting tests in a test submodule is that you can turn off the tests. In DrRacket’s Language menu, select Choose Language, click Show Details, click Submodules to run, and then uncheck the test item.

A Plait module’s definitions are automatically exported from the module. You can import the definitions of another module by using the require form, typically with a string that is a relative path to the module to import.

"math.rkt"

#lang plait
(define pi 3.14)
(define tau (+ pi pi))

"circle.rkt"

#lang plait
(require "math.rkt")
 
(define (circle-area [r : Number]) : Number
  (* pi (* r r)))

A submodule created by module+ automatically imports the bindings of the enclosing module, which is why (module+ test ....) submodules can automatically access definitions for testing. In contrast, if you write definitions inside (module+ test ....), then the definitions can be used for tests in any (module+ test ....), but the enclosing module will not see the definitions.

1.14 State

Warning: If you are using Plait with a programming-languages course, then the instructor has almost certainly disallowed the constructs in this chaper for use in your homework solutions, except as specifically allowed. Don’t use set!, begin, boxes, or vectors unless the instructor says that you can. If you’re tempted to use one of those, you’re doing it wrong.

We have so far described define as naming constants, but names bound by define are not necessarily constant. The value associated to the name can be changed using set!.

> (define gravity 6.6e-11)
> gravity

- Number

6.6e-11

> (set! gravity 6.5e-11)

- Void

> gravity

- Number

6.5e-11

The type of a set! expression is Void, meaning that it doesn’t return a useful value, and the useless value doesn’t even print as a result. If you need to change a variable and then return a value, use begin to sequence the operations. The value of a begin form is the value of its last expression.

> (define counter 0)
> (define (fresh-number!)
    (begin
      (set! counter (add1 counter))
      counter))
> (fresh-number!)

- Number

1

> (fresh-number!)

- Number

2

The ! at the end of fresh-number! is a convention to warn readers that calling the function can have a side effect.

Although you can set a variable’s value using set!, you can’t directly pass a variable to another function that changes the variable’s value. A set! on a function’s argument would change the argument variable’s value, but would have no effect on the caller’s variables. To make a mutable location that can be passed around, Plait supports boxes. You can think of a box as a mutable object that has a single field, where box creates a fresh object, unbox extracts the object’s field, and set-box! changes the object’s field.

> (define counter1 (box 0))
> (define counter2 (box 0))
> (define (fresh-number-at! c)
    (begin
      (set-box! c (add1 (unbox c)))
      (unbox c)))
> (fresh-number-at! counter1)

- Number

1

> (fresh-number-at! counter1)

- Number

2

> (fresh-number-at! counter2)

- Number

1

> (fresh-number-at! counter1)

- Number

3

A vector is a traditional mutable array. Every element of a vector must have the same type, which can be inferred from the value that you suply when making a vector to serve as the initial value for each of the vector’s slots. The vector function creates a vector, vector-ref accesses a slot value by position, and vector-set! changes a slot value by position.

> (define counters (make-vector 2 0))
> (define (fresh-number-at-index! i)
    (begin
      (vector-set! counters i (add1 (vector-ref counters i)))
      (vector-ref counters i)))
> (fresh-number-at-index! 0)

- Number

1

> (fresh-number-at-index! 0)

- Number

2

> (fresh-number-at-index! 1)

- Number

1

> (fresh-number-at-index! 0)

- Number

3

2 Definitions

The body of a plait module is a sequence of definitions, expressions and type declarations. The module implicitly exports all top-level definitions. When a plait module is imported into a module that does not use plait, the imports have contracts (matching reflecting the exported bindings’ types).

syntax

(id : type)

Declares that id has type type. This type declaration and the definition of id must be within the same definition sequence, either at the top of a module or together in a set of local definitions.

Added in version 1.1 of package plait.

syntax

(define id expr)

(define id : type expr)
(define (id id/type ...) expr)
(define (id id/type ...) : type expr)
 
id/type = id
  | [id : type]

For an introduction, see the tutorial section Definitions.

Defines id.

The expr in each of the first two forms is evaluated to get the value of id. In the first form, the type of id is inferred at the type of expr, while the second form declares a specific type for id.

The third and fourth forms define id as a function, where each id/type is a function argument (with an optional declare type) and expr is the body of the function, which is evaluated when the function is called. In the fourth form, a type before the body expr declares the function’s result type (which must match the type of expr).

Note that the first and second forms of define also define functions in the case that expr produces a function, such as when expr is a lambda form. The third and fourth forms are simplify shorthands for defining a function.

Evaluating a reference to id before its definition is evaluated triggers an “undefined identifier” error.

Examples:
> (define a 1)
> a

- Number

1

> (define b : Number (+ 1 2))
> b

- Number

3

> (define (c x)
    (+ x b))
> (c 3)

- Number

6

> (define (d [y : Number]) : Number
    (c y))
> (d 4)

- Number

7

syntax

(define-values (id/type ...) expr)

 
id/type = id
  | [id : type]

For an introduction, see the tutorial section Tuples and Options.

Defines each id/type (with an optional type declaration) to be the values within the tuple produced by expr, which must have as many values as declared id/types.

Examples:
> (define t (values 1 'one "One"))
> (define-values (a b c) t)
> a

- Number

1

> (define-values ([x : Number] [b : Symbol] [c : String]) t)
> c

- String

"One"

syntax

(define-type tyid/abs
  (variant-id [field-id : type])
  ...)
 
tyid/abs = id
  | (id 'arg-id ...)

For an introduction, see the tutorial section Datatypes.

Defines a type (when tyid/abs is id) or type constructor (when tyid/abs has the form (id 'id ...)).

A constructor variant-id is defined for each variant. Each constructor takes an argument for each field of its variant, where the type of each field is declared by the type after each field-id. The result type of each constructor is id.

Instances of a type declared with define-type are normally used through type-case.

In addition to the type and constructors, a define-type expression also defines:

Examples:
> (define-type Shape
    (circle [radius : Number])
    (rectangle [width : Number]
               [height : Number]))
> (define cr (circle 10))
> cr

- Shape

(circle 10)

> (circle? cr)

- Boolean

#t

> (circle-radius cr)

- Number

10

> (define rc (rectangle 2 3))
> (+ (rectangle-width rc) (rectangle-height rc))

- Number

5

syntax

(define-type-alias tyid/abs type)

 
tyid/abs = id
  | (id 'arg-id ...)
Defines a type alias id. When tyid/abs is id, then using id is the same as using type. When tyid/abs is (id 'arg-id ...), then using (id arg-type ...) is the same as using type with each 'arg-id replaced by the corresponding arg-type.

Examples:
> (define-type-alias Size Number)
> (define (square-area [side : Size])
    (* side side))
> (square-area 10)

- Number

100

Except for arg-ids, the type form must not reference any type variables that do not yet have a scope.

syntax

(require spec ...)

 
spec = module-path
  | (typed-in module-path [id : type] ...)
  | (opaque-type-in module-path [type-id predicate-id] ...)
  | (rename-in spec [orig-id new-id] ...)

For an introduction, see the tutorial section Programs and Modules.

Imports from each module-path.

When a module-path is not wrapped with typed-in or opaque-type-in, then module-path must refer to a module that is implemented with plait.

When module-path is wrapped with typed-in, then only the specified ids are imported from module-path, and the type system assumes (without static or additional dynamic checks) the given type for each id.

When module-path is wrapped with opaque-type-in, then the corresponding type-ids are bound as opaque datatypes, where predicate-id from module-path is a run-time predicate (used for contracts as needed for cooperation with untyped code) for instances of the datatype.

Examples:
> (require (typed-in racket/base [gensym : (-> Symbol)]))
> (gensym)

- Symbol

'g11816

syntax

(trace id ...)

For an introduction, see the tutorial section Testing and Debugging.

Traces subsequent calls—showing arguments and results—for functions bound to the ids. This form can be used only in a module top level, and only for tracing functions defined within the module.

syntax

(module id module-path form ...)

Declares a submodule named id, which can be required in the enclosing module using 'id or (submod "." id):

(module sub plait
  (define n 8))
(require 'sub)
(+ n 1)

syntax

(module+ id form ...)

For an introduction, see the tutorial section Programs and Modules.

Declares/extends a submodule named id, which is particularly useful for defining a test submodule to hold tests that precede relevant definitions (since the submodule implicitly imports the bindings of its enclosing module, and DrRacket or raco test runs the test submodule):

(module+ test
  (test 11 (add-one 10)))
 
(define (add-one n)
  (+ 1 n))

syntax

(include path-spec)

Copy the content of path-spec in place of the include form, which can only be used in a top-level position.

syntax

(define-syntax-rule (id pattern ...) template)

syntax

(define-syntax id macro-expr)

(define-syntax (id arg-id) macro-body ...)
 
macro = (syntax-rules ....)
  | (lambda ....)
Defines a macro. In a macro-expr or macro-body, the bindings of racket/base are available.

A macro of the form

(define-syntax-rule (id pattern ...) template)

is equivalent to

(define-syntax id
  (syntax-rules ()
   [(id pattern ...) template]))

syntax

(splice form ...)

Equivalent to the forms sequence in a module or top-level context, which is useful for producing multiple definitions from a macro.

3 Expressions

An expression can be a literal constant that is a number (type Number), a string (type String), a symbol (type Symbol) written with quote or ', an S-expression (type S-Exp) written with quasiquote or `, #t (type Boolean), #f (type Boolean), or a character (type Char). An expression also can be a bound identifier (in which case its type comes from its binding).

syntax

....

The .... form is intended as a placeholder for a expression. It can be used in any expression position and can have any type, but .... reports an error when evaluated.

Examples:
> (if #f .... 'ok)

- Symbol

'ok

> (if #t .... 'no)

- Symbol

reached a `....` placeholder

syntax

(has-type expr : type)

Equivalent to expr, but declares/asserts that expr has type type.

Examples:
> (has-type 1 : Number)

- Number

1

> (has-type "a" : Number)

eval:24:0: typecheck failed: String vs. Number

  sources:

   "a"

   Number

syntax

(quote q-form)

 
q-form = id
  | Number
  | String
  | Boolean
  | (q-form ...)
  | #(q-form ...)
  | #&q-form

For an introduction, see the tutorial section Lists.

The quote form is usually written as just a ' before a q-form; that is, 'id and (quote id) are equivalent.

The quote form produces a symbol, number, string, boolean, list, vector, or box value:

Beyond the syntactic contraints of q-form, the resulting list must have a type. So, for example, quote cannot create a list that mixes numbers and symbols.

Examples:
> 'a

- Symbol

'a

> '(1 2 3)

- (Listof Number)

'(1 2 3)

> '(1 a)

eval:27:0: typecheck failed: Number vs. Symbol

  sources:

   (quote (1 a))

   1

   a

> '((a) (b c))

- (Listof (Listof Symbol))

'((a) (b c))

syntax

(quasiquote qq-form)

 
qq-form = id
  | Number
  | String
  | Boolean
  | (qq-form ...)
  | (unquote expr)
  | (unquote-splicing expr)
  | (quasiquote expr)

syntax

unquote

syntax

unquote-splicing

For an introduction, see the tutorial section S-Expressions.

The quasiquote form is similar to quote, but it produces an S-expression, and it supports escapes via unquote and unquote-splicing. A (unquote expr) form is replaced with the value of expr, while a (unquote-splicing expr) form requires that expr produces a list and is replaced by the list content as an inlined sequence of S-expressions.

The quasiquote form is usually written as just a ` before qq-form; that is, 'qq-form and (quasiquote qq-form) are equivalent.

The unquote form is usually written as just a , before expr; that is, ,expr and (unquote expr) are equivalent.

The unquote-splicing form is usually written as just a ,@ before expr; that is, ,@expr and (unquote-splicing expr) are equivalent.

With a nested quasiquote form, escapes are preserved while escaping to the enclosing level of quotation. For example, ``(,(+ 1 2)) is equivalent to '(quasiquote (unquote 1)) where the quasiquote and unquote symbols are preserved in the result S-expression.

Examples:
> `a

- S-Exp

`a

> `(1 a)

- S-Exp

`(1 a)

> `(+ ,(number->s-exp (+ 1 2)) 3)

- S-Exp

`(+ 3 3)

> `(+ ,@(list `1 `2) 3)

- S-Exp

`(+ 1 2 3)

syntax

(#%app expr expr ...)

A function call, which is normally written without the #%app keyword.

Example:
> (add1 1)

- Number

2

syntax

(lambda (id/ty ...) expr)

(lambda (id/ty ...) : type expr)
 
id/ty = id
  | [id : type]

For an introduction, see the tutorial section Anonymous Functions.

An anonymous function which takes as many argument as specified id/tys and produces the result of expr. Each argument has an optional type specification, and when a type is written after (id/ty ...), it declares the result type of the function.

Examples:
> (lambda (x) (+ x 1))

- (Number -> Number)

#<procedure>

> (lambda ([x : Number]) (+ x 1))

- (Number -> Number)

#<procedure>

> ((lambda (x) (+ x 1)) 3)

- Number

4

> (map (lambda (x) (+ x 1)) (list 1 2 3))

- (Listof Number)

'(2 3 4)

syntax

λ

An alias for lambda.

syntax

(if test-expr expr expr)

syntax

(cond [test-expr expr] ...)

(cond [test-expr expr] ... [else expr])

For an introduction, see the tutorial section Conditionals.

An if form produces the value of the first expr if test-expr produces true or the value of the second expr otherwise. Only one of the two exprs is evaluated.

A cond form produces the value of the first expr whose test-expr produces true. The test-exprs are tried in order until a true result is found, and at most one of the exprs is evaluated. If no test-expr produces a true result, a “no matching clause“ exception is raised. An else in place of the last test-expr is equivalent to #t.

Each test-expr must have type Boolean.

Examples:
> (if (< 1 2)
      'less
      'greater-or-equal)

- Symbol

'less

> (cond
   [(< 2 1) 'bad]
   [(< 2 2) (begin (/ 1 0) 'oops)]
   [(< 2 3) 'ok]
   [(< 2 (/ 1 0)) 'oops]
   [else (begin (/ 1 0) 'oops)])

- Symbol

'ok

syntax

(case val-expr [(id-or-number ...) expr] ...)

(case val-expr [(id-or-number ...) expr] ... [else expr])
Performs a case dispatch on a symbol or number. The value of the case form is the value of an expr whose (id-or-number ...) sequence includes the result of val-expr, when symbols are matched to identifiers. If no id-or-number matches, a “no matching clause“ exception is raised.

The dispatching mode, symbol or number, is inferred from the id-or-numbers, which must all be symbols or numbers for a given use of case. If no clause provides a number or symbol, then symbol dispatch is inferred.

Examples:
> (case (+ 1 2)
    [(0 1 2) 'too-small]
    [(3) 'ok]
    [else 'other])

- Symbol

'ok

> (case 'goodbye
    [(hello) 'hi]
    [(goodbye) 'bye])

- Symbol

'bye

syntax

(begin expr ...+)

For an introduction, see the tutorial section State.

Evaluates the exprs in sequence, producing the result of the last expr.

Example:
> (+ (begin
      (display "hi\n")
      1)
     (begin
      (display "bye\n")
      2))

- Number

hi

bye

3

syntax

(when test-expr expr ...+)

syntax

(unless test-expr expr ...+)

Conditionally evaluates exprs for their side effects, always returning (void). A when form evaluates its exprs only test-expr produces true, while an unless form evaluates its exprs only test-expr produces false.

Examples:
> (when (< 1 2) (display "yes"))

- Void

yes

> (unless (< 1 2) (display "no"))

- Void

syntax

(local [definition-or-type-declaration ...] expr)

syntax

(letrec ([id rhs-expr] ...) expr)

syntax

(let ([id rhs-expr] ...) expr)

syntax

(let* ([id rhs-expr] ...) expr)

For an introduction, see the tutorial section Definitions.

Local binding forms. The local form accommodates multiple definitions and type declarations (using :) that are visible only among the definitions and the body expr. The letrec, let, and let* forms bind each id to the value of the corresponding rhs-expr (where the rhs-exprs are evaluated in order). In the case of letrec, each id is visible to every rhs-expr as well as in the body expr. In the case of let, each id is visible only in the body expr. In the case of let*, each id is visible only to later rhs-exprs as well as in the body expr.

Examples:
> (local [(add-x : (Number -> Number))
          (x : Number)
          (define (add-x y) (+ x y))
          (define x 2)]
    (add-x 3))

- Number

5

> add-x

eval:46:0: add-x: free variable while typechecking

  in: add-x

> (letrec ([add-x (lambda (y) (+ x y))]
           [x 2])
    (add-x 3))

- Number

5

> (let ([x 1])
    (let ([add-x (lambda (y) (+ x y))]
          [x 2])
     (add-x 3)))

- Number

4

> (let ([x 1])
    (let* ([add-x (lambda (y) (+ x y))]
           [x 2])
     (add-x 3)))

- Number

4

> (let ([x 1])
    (let* ([x 2]
           [add-x (lambda (y) (+ x y))])
     (add-x 3)))

- Number

5

syntax

(shared ([id expr] ...) expr)

Creates cyclic data for a restricted set of restricted expr patterns. See shared from racket/shared for a description of allowed patterns, besides the additional restriction that the form must be typed.

Example:
> (shared ([infinite-ones (cons 1 infinite-ones)])
    (list-ref infinite-ones 1001))

- Number

1

syntax

(parameterize ([param-expr val-expr] ...) expr)

The parameterize form implements a kind of dynamic binding. Each param-expr must have type (Parameterof type) where the corresponding val-expr has type type, and the parameter produces by param-expr is set to val-expr for the dynamic extent of expr.

Examples:
> (define current-mode (make-parameter 'straight))
> (define (display-line)
    (display (case (parameter-ref current-mode)
              [(straight) "---"]
              [(curvy) "~~~"])))
> (parameterize ([current-mode 'curvy])
    (display-line))

- Void

~~~

> (display-line)

- Void

---

> (define f
    (parameterize ([current-mode 'curvy])
      (lambda () (display-line))))
> (f)

- Void

---

syntax

(set! id expr)

For an introduction, see the tutorial section State.

Mutates id to have the value of expr.

Examples:
> (define x 1)
> (set! x (+ 1 1))

- Void

> x

- Number

2

syntax

(and expr ...)

syntax

(or expr ...)

For an introduction, see the tutorial section Conditionals.

Boolean combinations with short-circuiting: as soon as an expr produces false in and or true in or, the remaining exprs are not evaluated. The value of (and) is true and (or) is false. The exprs must have type Boolean.

Examples:
> (and (< 1 2) (< 3 4))

- Boolean

#t

> (and (< 2 1) (< 3 (/ 1 0)))

- Boolean

#f

> (or (< 2 1) (< 3 4))

- Boolean

#t

> (or (< 2 1) (< 1 2) (< 3 (/ 1 0)))

- Boolean

#t

syntax

(list elem ...)

For an introduction, see the tutorial section Lists.

Builds a list. All elems must have the same type.

Examples:
> (list 1 2 3)

- (Listof Number)

'(1 2 3)

> (list "a" "b")

- (Listof String)

'("a" "b")

> (list (list 1 2) empty (list 3 4))

- (Listof (Listof Number))

'((1 2) () (3 4))

syntax

(vector elem ...)

For an introduction, see the tutorial section State.

Builds a vector. All elems must have the same type.

Examples:
> (vector 1 2 3)

- (Vectorof Number)

'#(1 2 3)

> (vector "a" "b")

- (Vectorof String)

'#("a" "b")

> (vector (list 1 2) empty (list 3 4))

- (Vectorof (Listof Number))

'#((1 2) () (3 4))

syntax

(values elem ...)

For an introduction, see the tutorial section Tuples and Options.

Combines multiple values into tuple, where a tuple containing one value is equivalent to the value. Match a tuple result using define-values.

The type of each elem is independent.

Example:
> (values 1 'two "three")

- (Number * Symbol * String)

(values 1 'two "three")

syntax

(type-case tyid/abs val-expr
  [(variant-id field-id ...) expr] ...)
(type-case tyid/abs val-expr
  [(variant-id field-id ...) expr] ...
  [else expr])
(type-case (Listof type) val-expr
  [list-variant expr] ...)
(type-case (Listof type) val-expr
  [list-variant expr] ...
  [else expr])
 
tyid/abs = id
  | (id type ...)
     
list-variant = empty
  | (cons first-id rest-id)

For an introduction, see the tutorial section Datatypes.

Dispatches based on the variant of the result of val-expr.

In the form that has tyid/abs, val-expr must have type tyid/abs, and tyid/abs must refer to a type defined via define-type. The result is the value of expr for the variant-id that is instantiated by val-expr or the expr in an else clause if no variant-id matches. Each field-id is bound to a corresponding (by position) value of a field within the variant instance for use in the same clause’s expr.

The number of field-ids must match the number of fields declared for variant-id in the definition of tyid/abs, and either every variant-id of tyid/abs must have a clause in the type-case form or an else clause must be present.

Examples:
> (define-type Shape
    (circle [radius : Number])
    (rectangle [width : Number]
               [height : Number]))
> (define (area [s : Shape])
    (type-case Shape s
      [(circle r) (* (* r r) 3.14)]
      [(rectangle w h) (* w h)]))
> (area (circle 1))

- Number

3.14

> (area (rectangle 2 3))

- Number

6

In the (Listof type) form, val-expr must have type (Listof type). Each non-else clause is either a (cons first-id rest-id) clause or an empty clause, and both most appear without else, or at most one of those can appear with else.

Examples:
> (define (my-length l)
    (type-case (Listof 'a) l
      [empty 0]
      [(cons a b) (+ 1 (my-length b))]))
> (length '(1 2 3))

- Number

3

> (length '(a b))

- Number

2

syntax

(try expr (lambda () handle-expr))

Either returns expr’s result or catches an exception raised by expr and calls handle-expr.

Examples:
> (try 1 (lambda () 2))

- Number

1

> (try (/ 1 0) (lambda () 2))

- Number

2

> (try (begin (error 'demo "oops") 1) (lambda () 2))

- Number

2

> (try (begin (error 'demo "oops") 1) (lambda () (/ 2 0)))

- Number

/: division by zero

syntax

(test expr expr)

syntax

(test/exn expr string-expr)

For an introduction, see the tutorial section Testing and Debugging.

The test form checks whether the value of the first expr matches the value of the second expr, and reports a test failure or success. If the results of the two exprs are numbers and either is inexact, the test passes as long as the difference between the numbers is less than 0.01.

The test/exn form checks whether the expr raises an exception whose error message includes the string produced by string-expr.

The test and test/exn forms have type Void, although they do not actually produce a void value; instead, they produce results suitable for automatic display through a top-level expression, and the Void type merely prevents your program from using the result.

See also print-only-errors and module+.

syntax

(time expr)

Shows the time taken to evaluate expr and returns the value of expr.

syntax

(let/cc id expr)

Equivalent to (call/cc (lambda (id) expr)).

4 Predefined Functions and Constants

4.1 Booleans

value

not : (Boolean -> Boolean)

Boolean negation.

Example:
> (not #t)

- Boolean

#f

4.2 Lists

value

empty : (Listof 'a)

value

empty? : ((Listof 'a) -> Boolean)

value

cons : ('a (Listof 'a) -> (Listof 'a))

value

cons? : ((Listof 'a) -> Boolean)

value

first : ((Listof 'a) -> 'a)

value

rest : ((Listof 'a) -> (Listof 'a))

Essential list primitives: a list is either empty or cons of an item onto a list. The empty? predicate recognizes the empty list, a cons recognizes any other list. The first and rest functions select back out the two arguments to cons.

Examples:
> empty

- (Listof 'a)

'()

> (cons 1 empty)

- (Listof Number)

'(1)

> (first (cons 1 empty))

- Number

1

> (rest (cons 1 empty))

- (Listof Number)

'()

> (define my-list (cons 1 (cons 2 (cons 3 empty))))
> my-list

- (Listof Number)

'(1 2 3)

> (first my-list)

- Number

1

> (rest my-list)

- (Listof Number)

'(2 3)

> (first (rest my-list))

- Number

2

> (define also-my-list (list 1 2 3))
> also-my-list

- (Listof Number)

'(1 2 3)

> (rest also-my-list)

- (Listof Number)

'(2 3)

value

second : ((Listof 'a) -> 'a)

value

third : ((Listof 'a) -> 'a)

value

fourth : ((Listof 'a) -> 'a)

value

list-ref : ((Listof 'a) Number -> 'a)

Shorthands for accessing the first of the rest of a list, and so on. The second argument to list-ref specifies the number of rests to use before a first, so it effectively counts list items from 0.

Examples:
> (define my-list (list 1 2 3))
> (second my-list)

- Number

2

> (list-ref my-list 2)

- Number

3

value

length : ((Listof 'a) -> Number)

Returns the number of items in a list.

Examples:
> (define my-list (cons 1 (cons 2 (cons 3 empty))))
> (length my-list)

- Number

3

value

append : ((Listof 'a) (Listof 'a) -> (Listof 'a))

Produces a list that has the items of the first given list followed by the items of the second given list.

Examples:
> (define my-list (list 1 2 3))
> (define my-other-list (list 3 4 5))
> (append my-list my-other-list)

- (Listof Number)

'(1 2 3 3 4 5)

> (append my-other-list my-list)

- (Listof Number)

'(3 4 5 1 2 3)

value

reverse : ((Listof 'a) -> (Listof 'a))

Returns a list that has the same elements as the given one, but in reverse order.

Example:
> (reverse (list 1 2 3))

- (Listof Number)

'(3 2 1)

value

member : ('a (Listof 'a) -> Boolean)

Determines whether a value is an item in a list. Item are compared using equal?.

Examples:
> (member 1 (list 1 2 3))

- Boolean

#t

> (member 4 (list 1 2 3))

- Boolean

#f

value

map : (('a -> 'b) (Listof 'a) -> (Listof 'b))

Applies a function in order to each element of a list and forms a new list with the results.

Examples:
> (map add1 (list 1 2 3))

- (Listof Number)

'(2 3 4)

> (map to-string (list 1 2 3))

- (Listof String)

'("1" "2" "3")

value

map2 : (('a 'b -> 'c) (Listof 'a) (Listof 'b) -> (Listof 'c))

Applies a function in order to each pair of elements from two lists in “parallel,” forming a new list with the results. An exception is raised if the two lists have different lengths.

Example:
> (map2 + (list 1 2 3) (list 3 4 5))

- (Listof Number)

'(4 6 8)

value

filter : (('a -> Boolean) (Listof 'a) -> (Listof 'a))

Returns a list containing (in order) the items of a given list for which a given function returns true.

Examples:
> (filter even? (list 1 2 3 4))

- (Listof Number)

'(2 4)

> (filter odd? (list 1 2 3 4))

- (Listof Number)

'(1 3)

value

foldl : (('a 'b -> 'b) 'b (Listof 'a) -> 'b)

value

foldr : (('a 'b -> 'b) 'b (Listof 'a) -> 'b)

Applies a function to an accumulated value and each element of a list, each time obtaining a new accumulated value. The second argument to foldl or foldr is the initial accumulated value, and it is provided as the first argument in each call to the given function. While foldl applies the function or items in the list from from to last, foldr applies the function or items in the list from last to first.

Examples:
> (foldl + 10 (list 1 2 3))

- Number

16

> (foldl (lambda (n r) (cons (to-string n) r)) empty (list 1 2 3))

- (Listof String)

'("3" "2" "1")

> (foldr (lambda (n r) (cons (to-string n) r)) empty (list 1 2 3))

- (Listof String)

'("1" "2" "3")

value

build-list : (Number (Number -> 'a) -> (Listof 'a))

Creates a list of items produced by calling a given function on numbers starting from 0 a given number of times.

Example:
> (build-list 5 (lambda (v) (* v 10)))

- (Listof Number)

'(0 10 20 30 40)

4.3 Numbers

value

+ : (Number Number -> Number)

value

- : (Number Number -> Number)

value

* : (Number Number -> Number)

value

/ : (Number Number -> Number)

value

modulo : (Number Number -> Number)

value

remainder : (Number Number -> Number)

value

min : (Number Number -> Number)

value

max : (Number Number -> Number)

value

floor : (Number -> Number)

value

ceiling : (Number -> Number)

value

add1 : (Number -> Number)

value

sub1 : (Number -> Number)

Standard arithmetic functions.

Examples:
> (+ 1 2)

- Number

3

> (- 10 9)

- Number

1

> (/ 10 5)

- Number

2

> (modulo 10 3)

- Number

1

> (remainder 10 3)

- Number

1

> (min 1 2)

- Number

1

> (max 1 2)

- Number

2

> (floor 10.1)

- Number

10.0

> (ceiling 10.1)

- Number

11.0

> (ceiling 10.1)

- Number

11.0

> (add1 10)

- Number

11

> (sub1 10)

- Number

9

value

= : (Number Number -> Boolean)

value

> : (Number Number -> Boolean)

value

< : (Number Number -> Boolean)

value

>= : (Number Number -> Boolean)

value

<= : (Number Number -> Boolean)

value

zero? : (Number -> Boolean)

value

odd? : (Number -> Boolean)

value

even? : (Number -> Boolean)

Standard Number comparisons and predicates.

Examples:
> (= 1 1)

- Boolean

#t

> (> 1 2)

- Boolean

#f

> (< 1 2)

- Boolean

#t

> (zero? 1)

- Boolean

#f

> (odd? 1)

- Boolean

#t

> (even? 1)

- Boolean

#f

4.4 Symbols

Compares symbols

Examples:
> (symbol=? 'apple 'apple)

- Boolean

#t

> (symbol=? 'apple 'Apple)

- Boolean

#f

Converts between symbols and strings.

Examples:
> (string->symbol "apple")

- Symbol

'apple

> (symbol->string 'apple)

- String

"apple"

4.5 Strings

Standard string primitives.

Examples:
> (string=? "apple" "apple")

- Boolean

#t

> (string-append "apple" "banana")

- String

"applebanana"

> (string-length "apple")

- Number

5

> (substring "apple" 1 3)

- String

"pp"

> (string-ref "apple" 0)

- Char

#\a

value

to-string : ('a -> String)

Converts any value to a printed form as a string.

Examples:
> (to-string 1)

- String

"1"

> (to-string 'two)

- String

"'two"

> (to-string "three")

- String

"\"three\""

> (to-string (list 1 2 3))

- String

"'(1 2 3)"

> (to-string `(1 two "three"))

- String

"`(1 two \"three\")"

4.6 Characters

value

char=? : (Char Char -> Boolean)

Compares characters.

Example:
> (char=? #\a #\b)

- Boolean

#f

value

string->list : (String -> (Listof Char))

value

list->string : ((Listof Char) -> String)

Converts between a string and a list of characters.

Examples:
> (string->list "apple")

- (Listof Char)

'(#\a #\p #\p #\l #\e)

> (list->string (list #\a #\b #\c))

- String

"abc"

4.7 S-Expressions

For an introduction, see the tutorial section S-Expressions.

A S-expression typically represents program text. For example, placing a ' in from of any plait expression (which is the same as wrapping it with quote) creates an S-expression that contains the identifiers (as symbols), parenthesization (as lists), and other constants as the expression text. Various plait values, including symbols, numbers, and lists, can be coerced to and from S-expression form.

The representation of an S-expression always reuses some other plait value, so conversion to and from an S-expression is a kind cast. For example, the s-exp-symbol? function determines whether an S-expression embeds an immediate symbol; in that case, s-exp->symbol extracts the symbol, while any other value passed to s-exp->symbol raises an exception. The symbol->s-exp function wraps a symbol as an S-expression.

For interoperability of S-expressions with untyped Racket programs, see s-exp-content and s-exp.

Checks whether an S-expression corresponds to a single symbol and casts it from or to such a form. If s-exp->symbol is given an S-expression for which s-exp-symbol? returns false, then s-exp->symbol raises an exception.

Examples:
> (s-exp-symbol? `apple)

- Boolean

#t

> (s-exp->symbol `apple)

- Symbol

'apple

> (s-exp->symbol `1)

- Symbol

s-exp->symbol: not a symbol: `1

> (symbol->s-exp 'apple)

- S-Exp

`apple

Checks whether an S-expression corresponds to a single symbol and casts it from or to such a form. If s-exp->number is given an S-expression for which s-exp-number? returns false, then s-exp->number raises an exception.

Examples:
> (s-exp-number? `1)

- Boolean

#t

> (s-exp->number `1)

- Number

1

> (number->s-exp 1)

- S-Exp

`1

Checks whether an S-expression corresponds to a single symbol and casts it from or to such a form. If s-exp->string is given an S-expression for which s-exp-string? returns false, then s-exp->string raises an exception.

Examples:
> (s-exp-string? `"apple")

- Boolean

#t

> (s-exp->string `"apple")

- String

"apple"

> (string->s-exp "apple")

- S-Exp

`"apple"

Checks whether an S-expression corresponds to a single symbol and casts it from or to such a form. If s-exp->boolean is given an S-expression for which s-exp-boolean? returns false, then s-exp->boolean raises an exception.

Examples:
> (s-exp-boolean? `#f)

- Boolean

#t

> (s-exp->boolean `#f)

- Boolean

#f

> (boolean->s-exp #f)

- S-Exp

`#f

> (s-exp-boolean? `false)

- Boolean

#f

> (s-exp-symbol? `false)

- Boolean

#t

value

s-exp-list? : (S-Exp -> Boolean)

value

s-exp->list : (S-Exp -> (Listof S-Exp))

value

list->s-exp : ((Listof S-Exp) -> S-Exp)

Checks whether an S-expression corresponds to a single symbol and casts it from or to such a form. If s-exp->list is given an S-expression for which s-exp-list? returns false, then s-exp->list raises an exception. A list produced by s-exp->list always contains S-expression items.

Examples:
> (s-exp-list? `(1 2 3))

- Boolean

#t

> (s-exp-list? `1)

- Boolean

#f

> (s-exp->list `(1 2 3))

- (Listof S-Exp)

(list `1 `2 `3)

> (list->s-exp (list `1 `2 `3))

- S-Exp

`(1 2 3)

> (list->s-exp (list 1 2 3))

eval:167:0: typecheck failed: S-Exp vs. Number

  sources:

   list->s-exp

   (list 1 2 3)

   1

For an introduction, see the tutorial section S-Expression Matching.

Compares the first S-expression, a pattern, to the second S-expression, a target.

To a first approximation, s-exp-match? is just equal? on the two S-expressions. Unlike equal?, however, certain symbols in the pattern and can match various S-expressions within the target.

For example, `NUMBER within a pattern matches any number in corresponding position within the target:

Examples:
> (s-exp-match? `(+ NUMBER NUMBER) `(+ 1 10))

- Boolean

#t

> (s-exp-match? `(+ NUMBER NUMBER) `(+ 1 x))

- Boolean

#f

> (s-exp-match? `(+ NUMBER NUMBER) `(- 1 10))

- Boolean

#f

The following symbol S-expressions are treated specially within the pattern:

Any other symbol in a pattern matches only itself in the target. For example, `+ matches only `+.

Examples:
> (s-exp-match? `NUMBER `10)

- Boolean

#t

> (s-exp-match? `NUMBER `a)

- Boolean

#f

> (s-exp-match? `SYMBOL `a)

- Boolean

#t

> (s-exp-match? `SYMBOL `"a")

- Boolean

#f

> (s-exp-match? `STRING `"a")

- Boolean

#t

> (s-exp-match? `STRING `("a"))

- Boolean

#f

> (s-exp-match? `ANY `("a"))

- Boolean

#t

> (s-exp-match? `ANY `10)

- Boolean

#t

> (s-exp-match? `any `10)

- Boolean

#f

> (s-exp-match? `any `any)

- Boolean

#t

> (s-exp-match? `(SYMBOL) `(a))

- Boolean

#t

> (s-exp-match? `(SYMBOL) `(a b))

- Boolean

#f

> (s-exp-match? `(SYMBOL SYMBOL) `(a b))

- Boolean

#t

> (s-exp-match? `((SYMBOL) SYMBOL) `((a) b))

- Boolean

#t

> (s-exp-match? `((SYMBOL) NUMBER) `((a) b))

- Boolean

#f

> (s-exp-match? `((SYMBOL) NUMBER ((STRING))) `((a) 5 (("c"))))

- Boolean

#t

> (s-exp-match? `(lambda (SYMBOL) ANY) `(lambda (x) x))

- Boolean

#t

> (s-exp-match? `(lambda (SYMBOL) ANY) `(function (x) x))

- Boolean

#f

> (s-exp-match? `(SYMBOL ...) `(a b))

- Boolean

#t

> (s-exp-match? `(a ...) `(a b))

- Boolean

#f

> (s-exp-match? `(a ...) `(a a))

- Boolean

#t

> (s-exp-match? `(a ...) `())

- Boolean

#t

> (s-exp-match? `(a ... b) `())

- Boolean

#f

> (s-exp-match? `(a ... b) `(b))

- Boolean

#t

> (s-exp-match? `(a ... b) `(a a a b))

- Boolean

#t

> (s-exp-match? `((a ...) b ...) `((a a a) b b b b))

- Boolean

#t

> (s-exp-match? `((a ...) b ...) `((a a a) b c b b))

- Boolean

#f

4.8 Vector

For an introduction, see the tutorial section State.

value

make-vector : (Number 'a -> (Vectorof 'a))

value

vector-ref : ((Vectorof 'a) Number -> 'a)

value

vector-set! : ((Vectorof 'a) Number 'a -> Void)

value

vector-length : ((Vectorof 'a) -> Number)

A vector is similar to a list, but it supports constant-time access to any item in the vector and does not support constant-time extension. In addition, vectors are mutable.

The make-vector function creates a vector of a given size and initializes all vector items to a given value. The vector-ref function accesses the value in a vector slot, and vector-set! changes the value in a slot. The vector-length function reports the number of slots in the vector.

Examples:
> (define vec (make-vector 10 "apple"))
> (vector-length vec)

- Number

10

> (vector-ref vec 5)

- String

"apple"

> (vector-set! vec 5 "banana")

- Void

> (vector-ref vec 5)

- String

"banana"

> (vector-ref vec 6)

- String

"apple"

4.9 Boxes

For an introduction, see the tutorial section State.

value

box : ('a -> (Boxof 'a))

value

unbox : ((Boxof 'a) -> 'a)

value

set-box! : ((Boxof 'a) 'a -> Void)

A box is like a vector with a single slot. Boxes are used primarily to allow mutation. For example, the value of a field in a variant instance cannot be modified, but the field’s value can be a box, and then the box’s content can be modified.

The box function creates a box with an initial value for its slot, unbox accesses the current value in a box’s slot, and set-box! changes the value.

Examples:
> (define bx (box "apple"))
> (define bx2 bx)
> (unbox bx)

- String

"apple"

> (set-box! bx "banana")

- Void

> (unbox bx)

- String

"banana"

> (unbox bx2)

- String

"banana"

4.10 Tuples

For an introduction, see the tutorial section Tuples and Options.

value

pair : ('a 'b -> ('a * 'b))

value

fst : (('a * 'b) -> 'a)

value

snd : (('a * 'b) -> 'b)

Shorthands for two-element tuples: the pair function creates a tuple, and the fst and snd functions access tuple items.

Examples:
> (define p (pair 1 "apple"))
> p

- (Number * String)

(values 1 "apple")

> (fst p)

- Number

1

> (snd p)

- String

"apple"

4.11 Optional Values

For an introduction, see the tutorial section Tuples and Options.

value

none : (-> (Optionof 'a))

value

some : ('a -> (Optionof 'a))

value

some-v : ((Optionof 'a) -> 'a)

value

none? : ((Optionof 'a) -> bool)

value

some? : ((Optionof 'a) -> bool)

Defined as
(define-type (Optionof 'a)
  (none)
  (some [v : 'a]))

4.12 Hash Tables

value

make-hash : ((Listof ('a * 'b)) -> (Hashof 'a 'b))

value

hash : ((Listof ('a * 'b)) -> (Hashof 'a 'b))

value

hash-ref : ((Hashof 'a 'b) 'a -> (Optionof 'b))

The make-hash function creates a mutable hash table that is initialized with a given mapping of keys to values (as a list of tuples pairing keys to values). The hash function similarly creates an immutable hash table that supports constant-time functional update.

The hash-ref function works on either kind of hash table to find the value for a given key. If the hash table contains a mapping for a given key, hash-ref returns the key’s value wrapped with some. Otherwise, hash-ref returns (none).

Examples:
> (define m-ht (make-hash (list (pair 1 "apple") (pair 2 "banana"))))
> (define i-ht (hash (list (pair 1 "apple") (pair 2 "banana"))))
> (hash-ref m-ht 1)

- (Optionof String)

(some "apple")

> (hash-ref i-ht 1)

- (Optionof String)

(some "apple")

> (hash-ref m-ht 3)

- (Optionof String)

(none)

value

hash-set! : ((Hashof 'a 'b) 'a 'b -> Void)

value

hash-remove! : ((Hashof 'a 'b) 'a -> Void)

Changes the mapping of a mutable hash table. The hash-set! operation adds or changes the value for a given key, while hash-remove! deletes the mapping (if any) of a given key.

Providing an immutable hash table triggers an exception.

Examples:
> (define m-ht (make-hash (list (pair 1 "apple") (pair 2 "banana"))))
> (hash-ref m-ht 1)

- (Optionof String)

(some "apple")

> (hash-ref m-ht 3)

- (Optionof String)

(none)

> (hash-set! m-ht 3 "coconut")

- Void

> (hash-set! m-ht 1 "Apple")

- Void

> (hash-ref m-ht 1)

- (Optionof String)

(some "Apple")

> (hash-ref m-ht 3)

- (Optionof String)

(some "coconut")

value

hash-set : ((Hashof 'a 'b) 'a 'b -> (Hashof 'a 'b))

value

hash-remove : ((Hashof 'a 'b) 'a -> (Hashof 'a 'b))

Produces an immutable hash table that is like a given one, but with a mapping changed, added, or removed. The hash-set operation adds or changes the value for a given key in the result hash table, while hash-remove deletes the mapping (if any) of a given key in the result hash table.

Examples:
> (define i-ht (hash (list (pair 1 "apple") (pair 2 "banana"))))
> (hash-ref i-ht 1)

- (Optionof String)

(some "apple")

> (define i-ht2 (hash-set (hash-set i-ht 1 "Apple")
                          3 "coconut"))
> (hash-ref i-ht2 1)

- (Optionof String)

(some "Apple")

> (hash-ref i-ht2 3)

- (Optionof String)

(some "coconut")

> (hash-ref i-ht 3)

- (Optionof String)

(none)

value

hash-keys : ((Hashof 'a 'b) -> (Listof 'a))

Returns the keys mapped by a hash table, which can be mutable or immutable.

Examples:
> (define i-ht (hash (list (pair 1 "apple") (pair 2 "banana"))))
> (hash-keys i-ht)

- (Listof Number)

'(1 2)

4.13 Parameters

value

make-parameter : ('a -> (Parameterof 'a))

value

parameter-ref : ((Parameterof 'a) -> 'a)

value

parameter-set! : ((Parameterof 'a) 'a -> Void)

A parameter implements a kind dynamic binding. The make-parameter function creates a fresh parameter, parameter-ref accesses the parameter’s current value, and parameter-set! changes the parameter’s current value (i.e., at the nearest dynamic binding established with parameterize, if any).

See also parameterize.

4.14 Equality

value

equal? : ('a 'a -> Boolean)

Compares two values for equality. Roughly, two values are equal? when they print the same, but opaque values such as functions are equal? only if they are eq?.

Examples:
> (equal? "apple" "apple")

- Boolean

#t

> (equal? (values 1 'two "three") (values 1 'two "three"))

- Boolean

#t

value

eq? : ('a 'a -> Boolean)

Checks whether two values are exactly the same value, which amounts to checking pointer equality. The eq? function is well-defined on symbols (where it is equivalent to equal?), mutable data structures (where pointer equality corresponds to shared mutation), and the result of a single expression (such as comparing a identifier’s value to itself), but it should be avoided otherwise.

Examples:
> (eq? 'apple 'apple)

- Boolean

#t

> (let ([get-one (lambda () 1)])
    (eq? get-one get-one))

- Boolean

#t

4.15 Other Functions

value

identity : ('a -> 'a)

Identity primitive.

value

error : (Symbol String -> 'a)

Error primitive.

value

display : ('a -> Void)

Output primitive.

value

read : (-> S-Exp)

Input primitive.

value

void : (-> Void)

Void primitive.

Enables or disables the printing of tests that pass. Tests that fail always cause printing.

value

call/cc : ((('a -> 'b) -> 'a) -> 'a)

Passes the current continuation to the given function, and returns that function’s result.

The current continuation is itself represented as a function. Applying a continuation function discards the current continuation and replaces it with the called one, supplying the given value to that continuation.

value

s-exp-content : no type

value

s-exp : no type

These functions have no type, so they cannot be used in a plait program. They can be used in untyped contexts to coerce a plait S-expression to a plain Racket S-expression and vice-versa.

value

tuple-content : no type

value

tuple : no type

These functions have no type, so they cannot be used in a plait program. They can be used in untyped contexts to coerce a plait tuple to an immutable vector and vice-versa.

5 Types

syntax

Number

syntax

Boolean

syntax

Symbol

syntax

String

syntax

Char

syntax

S-Exp

syntax

Void

Primitive types.

syntax

(type ... -> type)

Type for functions. Each type before the -> corresponds to a function argument, and the type after -> corresponds to a function result.

syntax

(type * ...+)

Type for tuples. Each *-separated type is the type of an element in the tuple.

syntax

()

Type for the empty tuple.

syntax

(Listof type)

Type for lists of elements, where type is the type of one element.

syntax

(Boxof type)

Type for mutable boxes, where type is the type of the box’s content.

syntax

(Vectorof type)

Type for vectors of elements, where type is the type of one element.

syntax

(Parameterof type)

Type for parameters, where type is the type of the parameter’s value.

syntax

(Hashof type type)

Type for hash tables, where the first type corresponds to keys and the second type correspond to values.

syntax

(Optionof type)

Defined as
(define-type (Optionof 'a)
  (none)
  (some [v : 'a]))
and used, for example, for the result of hash-ref.

syntax

'id

A type variable that stands for an unspecified type. The type checker effectively replaces each type variable with some other type—but possibly another type variable that is bound by an inferred polymorphic type.

In the following example, the type checker determines that 'a must be replaced with Number:

> (define one : 'a 1)
> one

- Number

1

In the following example, the type checker determines that 'b stands for the argument type of a polymorphic function:

> (define (f [x : 'b]) x)

In the following examples, the type checker is unable to replace 'a consistently with the same type everywhere:

> (if (has-type #t : 'a) (has-type 1 : 'a) 2)

eval:240:0: typecheck failed: Number vs. Boolean

  sources:

   1

   #t

   a

> (define x : 'a (list (has-type 1 : 'a)))

eval:241:0: typecheck failed: Number vs. (Listof Number)

  sources:

   (list (has-type 1 : (quote a)))

Multiple uses of the same type variable (i.e., with the same id) are constrained to refer to the same type only when the uses have the same scope. A type variable’s scope is determined as follows:

For example, type variables introduced in separate definitions are always distinct, so in the following example, the first 'a can stand for Number while the second stands for String:

> (define one : 'a 1)
> (define two : 'a "two")

A type variable used for a lambda argument is scoped to the entire lambda form, so the uses of 'a in the definitions of the following example refer back to that argument type, and the argument cannot have both Number and String type:

> (lambda ([x : 'a])
    (local [(define one : 'a 1)
            (define two : 'a "two")]
      #f))

eval:244:0: typecheck failed: Number vs. String

  sources:

   "two"

   1

   a

Beware that the order of expressions can affect the scope of type variables within the expressions:

> (values
    (has-type 1 : 'a)
    (letrec ([f (lambda ([x : 'a]) x)]) f))

- (Number * (Number -> Number))

(values 1 #<procedure:f>)

> (values
    (letrec ([f (lambda ([x : 'a]) x)]) f)
    (has-type 1 : 'a))

- (('_a -> '_a) * Number)

(values #<procedure:f> 1)

6 Syntactic Literals

syntax

typed-in

syntax

opaque-type-in

syntax

:

Syntactic literals are for use in declarations such as define and require; see define and require for more information. A : can also be used for a type declaration within a definition sequence; see Definitions.

7 Type Checking and Inference

Type checking and inference is just as in ML (Hindley-Milner), with a few small exceptions:

When typechecking fails, the error messages reports and highlights (in pink) all of the expressions whose type contributed to the failure. That’s often too much information. As usual, explicit type annotations can help focus the error message.

8 Untyped, Lazy, and Fuel Modes

Use #:untyped immediately after #lang plait to disable type checking. The syntax of a plait module is the same with and without #:untyped, but types are ignored when #:untyped is specified. An untyped Plait module can interoperate with a typed Plait module, and dynamic checks are inserted at the boundary to protect typed functions from abuse by untyped code.

Use #:lazy immediately after #lang plait to switch evaluation to lazy mode. The syntax and type system are unchanged, but argument expressions for function calls are evaluated only when forced (by a test or by printing, ultimately). A lazy Plait module will not interoperate well with an eager module.

Use #:fuel amount immediately after #lang plait to specify how much effort should be spent resolving potentially cyclic dependencies due to inference of polymorphic recursion. The default fuel is 100.

The #:untyped, #:lazy, and #:fuel modifiers can be combined, and the combination can be declared in any order.