Next: Sequencing, Previous: Conditionals, Up: Core syntax [Contents][Index]

- Special Form:
**let***((var expr) …) body …* - Special Form:
**let****((var expr) …) body …* - Special Form:
**letrec***((var expr) …) body …* - Special Form:
**letrec****((var expr) …) body …* [R7RS] Creates a local scope where

`var`… are bound to the value of`expr`…, then evaluates`body`….`var`s must be symbols, and there shouldn’t be a duplication. The value(s) of the last expression of`body`… becomes the value(s) of this form.The four forms differ in terms of the scope and the order

`expr`s are evaluated.`Let`

evaluates`expr`s before (outside of)`let`

form. The order of evaluation of`expr`s is undefined, and the compiler may reorder those`expr`s freely for optimization.`Let*`

evaluates`expr`s, in the order they appears, and each`expr`is evaluated in the scope where`var`s before it are bound.`Letrec`

evaluates`expr`s, in an undefined order, in the environment where`var`s are already bound (to an undefined value, initially).`letrec`

is necessary to define mutually recursive local procedures. Finally,`letrec*`

uses the same scope rule as`letrec`

, and it evaluates`expr`in the order of appearance.(define x 'top-x) (let ((x 3) (y x)) (cons x y)) ⇒ (3 . top-x) (let* ((x 3) (y x)) (cons x y)) ⇒ (3 . 3) (let ((cons (lambda (a b) (+ a b))) (list (lambda (a b) (cons a (cons b 0))))) (list 1 2)) ⇒ (1 2 . 0) (letrec ((cons (lambda (a b) (+ a b))) (list (lambda (a b) (cons a (cons b 0))))) (list 1 2)) ⇒ 3

You need to use

`letrec*`

if evaluation of one`expr`requires the value of`var`that appears before the`expr`. In the following example, calculating the value of`a`and`b`requires the value of`cube`, so you need`letrec*`

. (Note the difference from the above example, where*calculating*the value of`list`doesn’t need to take the value of`cons`bound in the same`letrec`

. The value of`cons`isn’t required until`list`is actually applied.)(letrec* ((cube (lambda (x) (* x x x))) (a (+ (cube 1) (cube 12))) (b (+ (cube 9) (cube 10)))) (= a b)) ⇒ #t

This example happens to work with

`letrec`

in the current Gauche, but it is not guaranteed to keep working in future. You just should not rely on evaluation order when you use`letrec`

. In retrospect, it would be a lot simpler if we only have`letrec*`

. Unfortunately`letrec`

preceded for long time in Scheme history and it’s hard to remove that. Besides,`letrec`

does have more opportunities to optimize than`letrec*`

.

- Macro:
**let1***var expr body …* A convenient macro when you have only one variable. Expanded as follows.

(let ((

`var``expr`))`body`…)

- Macro:
**if-let1***var expr then* - Macro:
**if-let1***var expr then else* This macro simplifies the following idiom:

(let1

`var``expr`(if`var``then``else`))

- Macro:
**rlet1***var expr body …* This macro simplifies the following idiom:

(let1

`var``expr``body`…`var`)

- Macro:
**and-let****(binding …) body …* [SRFI-2] In short, it works like

`let*`

, but returns`#f`

immediately whenever the expression in`binding`s evaluates to`#f`

.Each

`binding`should be one of the following form:`(`

`variable``expression`)The

`expression`is evaluated; if it yields true value, the value is bound to`variable`, then proceed to the next binding. If no more bindings, evaluates`body`…. If`expression`yieds`#f`

, stops evaluation and returns`#f`

from`and-let*`

.`(`

`expression`x)In this form,

`variable`is omitted.`Expression`is evaluated and the result is used just to determine whether we continue or stop further evaluation.`bound-variable`In this form,

`bound-variable`should be an identifier denoting a bound variable. If its value is not`#f`

, we continue the evaluation of the clauses.

Let’s see some examples. The following code searches

`key`from an assoc-list`alist`and returns its value if found.(and-let* ((entry (assoc key alist))) (cdr entry))

If

`arg`is a string representation of an exact integer, returns its value; otherwise, returns 0:(or (and-let* ((num (string->number arg)) ( (exact? num) ) ( (integer? num) )) num) 0)

The following is a hypothetical code that searches a certain server port number from a few possibilities (environment variable, configuration file, ...)

(or (and-let* ((val (sys-getenv "SERVER_PORT"))) (string->number val)) (and-let* ((portfile (expand-path "~/.server_port")) ( (file-exists? portfile) ) (val (call-with-input-string portfile port->string))) (string->number val)) 8080) ; default

- Macro:
**and-let1***var test exp1 exp2 …* Evaluates

`test`, and if it isn’t`#f`

, binds`var`to it and evaluates`exp1``exp2`…. Returns the result(s) of the last expression. If`test`evaluates to`#f`

, returns`#f`

.This can be easily written by

`and-let*`

or`if-let1`

as follows. However, we’ve written this idiom so many times that it deserves another macro.(and-let1 var test exp1 exp2 …) ≡ (and-let* ([var test]) exp1 exp2 …) ≡ (if-let1 var test (begin exp1 exp2 …) #f)

- Macro:
**fluid-let***((var val) …) body …* A macro that emulates dynamic scoped variables.

`Var`s must be variables bound in the scope including`fluid-let`

form.`Val`s are expressions.`Fluid-let`

first evaluates`val`s, then evaluates`body`…, with binding`var`s to the corresponding values during the dynamic scope of`body`….Note that, in multithreaded environment, the change of the value of

`var`s are visible from all the threads. This form is provided mainly for the porting convenience. Use parameter objects instead (see Parameters) for thread-local dynamic state.(define x 0) (define (print-x) (print x)) (fluid-let ((x 1)) (print-x)) ⇒ ;; prints 1

- Special Form:
**receive***formals expression body …* [SRFI-8] This is the way to receive multiple values.

`Formals`can be a (maybe-improper) list of symbols.`Expression`is evaluated, and the returned value(s) are bound to`formals`like the binding of lambda formals, then`body`… are evaluated.(define (divrem n m) (values (quotient n m) (remainder n m))) (receive (q r) (divrem 13 4) (list q r)) ⇒ (3 1) (receive all (divrem 13 4) all) ⇒ (3 1) (receive (q . rest) (divrem 13 4) (list q rest)) ⇒ (3 (1))

See also

`call-with-values`

in Multiple values which is the procedural equivalent of`receive`

. You can use`define-values`

(see Definitions) to bind multiple values to variables simultaneously. Also`let-values`

and`let*-values`

in SRFI-11 (Let-values) provides`let`

-like syntax with multiple values.

- Macro:
**rec***var expr* - Macro:
**rec***(name . vars) expr …* [SRFI-31] A macro to evaluate an expression with recursive reference.

In the first form, evaluates expr while

`var`in`expr`is bound to the result of`expr`. The second form is equivalent to the followings.(rec

`name`(lambda`vars``expr`…))Some examples:

;; constant infinite stream (rec s (cons 1 (delay s))) ;; factorial function (rec (f n) (if (zero? n) 1 (* n (f (- n 1)))))

Next: Sequencing, Previous: Conditionals, Up: Core syntax [Contents][Index]