9.1 KiB
Definitions: define
A basic definition has the form
(define id expr)
in which case id
is bound to the result of expr
.
Examples:
(define salutation (list-ref '("Hi" "Hello") (random 2)))
> salutation
"Hi"
1. Function Shorthand
The define
form also supports a shorthand for function definitions:
(define (id arg ...) body ...+)
which is a shorthand for
(define
id
(lambda
(arg
...)
body
...+))
Examples:
(define (greet name)
(string-append salutation ", " name))
> (greet "John")
"Hi, John"
(define (greet first [surname "Smith"] #:hi [hi salutation])
(string-append hi ", " first " " surname))
> (greet "John")
"Hi, John Smith"
> (greet "John" #:hi "Hey")
"Hey, John Smith"
> (greet "John" "Doe")
"Hi, John Doe"
The function shorthand via define
also supports a rest argument
i.e., a final argument to collect extra arguments in a list
:
(define (id arg ... . rest-id) body ...+)
which is a shorthand
(define
id
(lambda
(arg
...
. rest-id)
body
...+))
Examples:
(define (avg . l)
(/ (apply + l) (length l)))
> (avg 1 2 3)
2
2. Curried Function Shorthand
Consider the following make-add-suffix
function that takes a string
and returns another function that takes a string:
(define make-add-suffix
(lambda (s2)
(lambda (s) (string-append s s2))))
Although it’s not common, result of make-add-suffix
could be called
directly, like this:
> ((make-add-suffix "!") "hello")
"hello!"
In a sense, make-add-suffix
is a function takes two arguments, but it
takes them one at a time. A function that takes some of its arguments
and returns a function to consume more is sometimes called a curried
function.
Using the function-shorthand form of define
, make-add-suffix
can be
written equivalently as
(define (make-add-suffix s2)
(lambda (s) (string-append s s2)))
This shorthand reflects the shape of the function call (make-add-suffix "!")
. The define
form further supports a shorthand for defining
curried functions that reflects nested function calls:
(define ((make-add-suffix s2) s)
(string-append s s2))
> ((make-add-suffix "!") "hello")
"hello!"
(define louder (make-add-suffix "!"))
(define less-sure (make-add-suffix "?"))
> (less-sure "really")
"really?"
> (louder "really")
"really!"
The full syntax of the function shorthand for define
is as follows:
(define (head args) body ...+)
head = id
| (head args)
args = arg ...
| arg ... . rest-id
The expansion of this shorthand has one nested lambda
form for each
head
in the definition, where the innermost head
corresponds to the
outermost lambda
.
3. Multiple Values and define-values
A Racket expression normally produces a single result, but some
expressions can produce multiple results. For example, quotient
and
remainder
each produce a single value, but quotient/remainder
produces the same two values at once:
> (quotient 13 3)
4
> (remainder 13 3)
1
> (quotient/remainder 13 3)
4
1
As shown above, the REPL prints each result value on its own line.
Multiple-valued functions can be implemented in terms of the values
function, which takes any number of values and returns them as the
results:
> (values 1 2 3)
1
2
3
(define (split-name name)
(let ([parts (regexp-split " " name)])
(if (= (length parts) 2)
(values (list-ref parts 0) (list-ref parts 1))
(error "not a <first> <last> name"))))
> (split-name "Adam Smith")
"Adam"
"Smith"
The define-values
form binds multiple identifiers at once to multiple
results produced from a single expression:
(define-values (id ...) expr)
The number of results produced by the expr
must match the number of
id
s.
Examples:
(define-values (given surname) (split-name "Adam Smith"))
> given
"Adam"
> surname
"Smith"
A define
form that is not a function shorthand
is equivalent to a
define-values
form with a single id
.
+[missing] in [missing] provides more on definitions.
4. Internal Definitions
When the grammar for a syntactic form specifies body
, then the
corresponding form can be either a definition or an expression. A
definition as a body
is an internal definition.
Expressions and internal definitions in a body
sequence can be mixed,
as long as the last body
is an expression.
For example, the syntax of lambda
is
(lambda gen-formals
body ...+)
so the following are valid instances of the grammar:
(lambda (f) ; no definitions
(printf "running\n")
(f 0))
(lambda (f) ; one definition
(define (log-it what)
(printf "~a\n" what))
(log-it "running")
(f 0)
(log-it "done"))
(lambda (f n) ; two definitions
(define (call n)
(if (zero? n)
(log-it "done")
(begin
(log-it "running")
(f n)
(call (- n 1)))))
(define (log-it what)
(printf "~a\n" what))
(call n))
Internal definitions in a particular body
sequence are mutually
recursive; that is, any definition can refer to any other definition—as
long as the reference isn’t actually evaluated before its definition
takes place. If a definition is referenced too early, an error occurs.
Examples:
(define (weird)
(define x x)
x)
> (weird)
x: undefined;
cannot use before initialization
A sequence of internal definitions using just define
is easily
translated to an equivalent letrec
form (as introduced in the next
section). However, other definition forms can appear as a body
,
including define-values
, struct
see \[missing\]
or
define-syntax
see \[missing\]
.
+[missing] in [missing] documents the fine points of internal definitions.