1 Welcome to PLT Scheme
2 Scheme Essentials
3 Built-In Datatypes
4 Expressions and Definitions
5 Programmer-Defined Datatypes
6 Modules
7 Contracts
8 Input and Output
9 Regular Expressions
10 Exceptions and Control
11 Iterations and Comprehensions
12 Pattern Matching
13 Classes and Objects
14 Units (Components)
15 Reflection and Dynamic Evaluation
16 Macros
17 Performance
18 Running and Creating Executables
19 Compilation and Configuration
20 More Libraries
Bibliography
Index
On this page:
4.5.1 Function Shorthand
4.5.2 Curried Function Shorthand
4.5.3 Multiple Values and define-values
4.5.4 Internal Definitions
Version: 4.0.2

 

4.5 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"

4.5.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

4.5.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.

4.5.3 Multiple Values and define-values

A Scheme 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 ids.

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.

Definitions: define, define-syntax, ... in Reference: PLT Scheme provides more on definitions.

4.5.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.

All internal definitions in a body sequence must appear before any expression, and the last body must be 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"))

    (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 0)

            (call (- n 1)))))

    (define (log-it what)

      (printf "~a\n"))

    (call f 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, the result is a special value #<undefined>.

Examples:

  (define (weird)

    (define x x)

    x)

  > (weird)

  #<undefined>

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, define-struct (see Programmer-Defined Datatypes) or define-syntax (see Macros).

Internal Definitions in Reference: PLT Scheme documents the fine points of internal definitions.