2 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-expression) also written with quote 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).
> (has-type 1 : number) - number
1
> (has-type "a" : number) eval:27.0: typecheck failed: string vs. number
sources:
"a"
number
syntax
(quote s-exp)
s-exp = id | number | string | boolean | (s-exp ...)
The quote form is usually written as just a ' before s-exp; that is, 's-exp and (quote s-exp) are equivalent.
Note that `id or (quasiquote id) produces a literal S-expression with symbol content, as opposed to producing a value of type symbol.
> 'a - symbol
'a
> '(a b c) - s-expression
'(a b c)
> `a - s-expression
'a
syntax
(quasiquote qq-form)
qq-form = id | number | string | boolean | (qq-form ...) | (unquote expr) | (unquote-splicing expr) | (quasiquote expr)
syntax
syntax
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.
An id (to generate a symbol S-expression) in a qq-form must not be unquote, unquote-splicing, or quasiquote.
> `(+ ,(number->s-exp (+ 1 2)) 3) - s-expression
'(+ 3 3)
> `(+ ,@(list '1 '2) 3) - s-expression
'(+ 1 2 3)
syntax
(#%app expr expr ...)
> (add1 1) - number
2
> (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
syntax
(if test-expr expr expr)
syntax
(cond [test-expr expr] ...)
(cond [test-expr expr] ... [else expr])
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 true.
Each test-expr must have type boolean.
> (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])
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.
> (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 ...+)
syntax
(local [definition ...] expr)
syntax
(letrec ([id rhs-expr] ...) expr)
syntax
(let ([id rhs-expr] ...) expr)
syntax
(let* ([id rhs-expr] ...) expr)
> (local [(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)
syntax
(parameterize ([param-expr val-expr] ...) expr)
> (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)
> (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 ...)
> (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 ...)
> (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 ...)
The type of each elem is independent.
> (values 1 'two "three") - (number * symbol * string)
'#(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])
tyid/abs = id | (id type ...)
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.
> (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
> (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
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)
syntax
(let/cc id expr)