A lambda expression evaluates to a procedure. The environment
which is in effect when a lambda expression is evaluated is
enclosed in the newly created procedure, this is referred to as a
closure (see section The Concept of Closure).
When a procedure created by lambda is called with some actual
arguments, the environment enclosed in the procedure is extended by
binding the variables named in the formal argument list to new locations
and storing the actual arguments into these locations. Then the body of
the lambda expression is evaluation sequentially. The result of
the last expression in the procedure body is then the result of the
procedure invocation.
The following examples will show how procedures can be created using
lambda, and what you can do with these procedures.
(lambda (x) (+ x x)) => a procedure ((lambda (x) (+ x x)) 4) => 8
The fact that the environment in effect when creating a procedure is enclosed in the procedure is shown with this example:
(define add4
(let ((x 4))
(lambda (y) (+ x y))))
(add4 6) => 10
(variable1 ...)
variable
(variable1 ... variablen . variablen+1)
body is a sequence of Scheme expressions which are evaluated in order when the procedure is invoked.
Scheme procedures, as defined in R5RS, can either handle a fixed number of actual arguments, or a fixed number of actual arguments followed by arbitrarily many additional arguments. Writing procedures of variable arity can be useful, but unfortunately, the syntactic means for handling argument lists of varying length is a bit inconvenient. It is possible to give names to the fixed number of argument, but the remaining (optional) arguments can be only referenced as a list of values (see section Lambda: Basic Procedure Creation).
Guile comes with the module (ice-9 optargs), which makes using
optional arguments much more convenient. In addition, this module
provides syntax for handling keywords in argument lists
(see section Keywords).
Before using any of the procedures or macros defined in this section,
you have to load the module (ice-9 optargs) with the statement:
(use-modules (ice-9 optargs))
The syntax let-optional and let-optional* are for
destructuring rest argument lists and giving names to the various list
elements. let-optional binds all variables simultaneously, while
let-optional* binds them sequentially, consistent with let
and let* (see section Local Variable Bindings).
(var
default-value). rest-arg should be the rest-argument of the
procedures these are used from. The items in rest-arg are
sequentially bound to the variable names are given. When rest-arg
runs out, the remaining vars are bound either to the default values or
left unbound if no default value was specified. rest-arg remains
bound to whatever may have been left of rest-arg.
After binding the variables, the expressions expr ... are evaluated in order.
let-keywords and let-keywords* are used for extracting
values from argument lists which use keywords instead of argument
position for binding local variables to argument values.
let-keywords binds all variables simultaneously, while
let-keywords* binds them sequentially, consistent with let
and let* (see section Local Variable Bindings).
lambda*
(see section lambda* Reference). bindings can have the same form as
for let-optional. If allow-other-keys? is false, an error
will be thrown if anything that looks like a keyword argument but does
not match a known keyword parameter will result in an error.
After binding the variables, the expressions expr ... are evaluated in order.
When using optional and keyword argument lists, using lambda for
creating procedures and using let-optional or let-keywords
is a bit lengthy. Therefore, lambda* is provided, which combines
the features of those macros into a single convenient syntax.
For quick reference, here is the syntax of the formal argument list for
lambda* (brackets are used to indicate grouping only):
ext-param-list ::= [identifier]* [#:optional [ext-var-decl]+]? [#:key [ext-var-decl]+ [#:allow-other-keys]?]? [[#:rest identifier]|[. identifier]]? ext-var-decl ::= identifier | ( identifier expression )
The characters `*', `+' and `?' are not to be taken literally; they mean respectively, zero or more occurrences, one or more occurrences, and one or zero occurrences.
lambda* creates a procedure that takes optional arguments. These
are specified by putting them inside brackets at the end of the
parameter list, but before any dotted rest argument. For example,
(lambda* (a b #:optional c d . e) '())
creates a procedure with fixed arguments a and b, optional
arguments c and d, and rest argument e. If the
optional arguments are omitted in a call, the variables for them are
unbound in the procedure. This can be checked with the bound?
macro (documented below).
lambda* can also take keyword arguments. For example, a procedure
defined like this:
(lambda* (#:key xyzzy larch) '())
can be called with any of the argument lists (#:xyzzy 11)
(#:larch 13) (#:larch 42 #:xyzzy 19) (). Whichever
arguments are given as keywords are bound to values.
Optional and keyword arguments can also be given default values which they take on when they are not present in a call, by giving a two-item list in place of an optional argument, for example in:
(lambda* (foo #:optional (bar 42) #:key (baz 73))
(list foo bar baz))
foo is a fixed argument, bar is an optional argument with default value 42, and baz is a keyword argument with default value 73. Default value expressions are not evaluated unless they are needed and until the procedure is called.
lambda* also supports two more special parameter list keywords.
lambda*-defined procedures now throw an error by default if a
keyword other than one of those specified is found in the actual
passed arguments. However, specifying #:allow-other-keys
immediately after the keyword argument declarations restores the
previous behavior of ignoring unknown keywords. lambda* also now
guarantees that if the same keyword is passed more than once, the
last one passed is the one that takes effect. For example,
((lambda* (#:key (heads 0) (tails 0)) (display (list heads tails)))
#:heads 37 #:tails 42 #:heads 99)
would result in (99 47) being displayed.
#:rest is also now provided as a synonym for the dotted syntax
rest argument. The argument lists (a . b) and (a #:rest b)
are equivalent in all respects to lambda*. This is provided for
more similarity to DSSSL, MIT-Scheme and Kawa among others, as well as
for refugees from other Lisp dialects.
The procedure defined? doesn't quite cut it as it stands, since
it only checks bindings in the top-level environment, not those in local
scope only.
Just like define has a shorthand notation for defining procedures
(see section Lambda Alternatives), define* is provided as an
abbreviation of the combination of define and lambda*.
define*-public is the lambda* version of
define-public; defmacro* and defmacro*-public exist
for defining macros with the improved argument list handling
possibilities. The -public versions not only define the
procedures/macros, but also export them from the current module.
define* and define*-public support optional arguments with
a similar syntax to lambda*. They also support arbitrary-depth
currying, just like Guile's define. Some examples:
(define* (x y #:optional a (z 3) #:key w . u) (display (list y z u)))
defines a procedure x with a fixed argument y, an optional
argument a, another optional argument z with default value 3,
a keyword argument w, and a rest argument u.
(define-public* ((foo #:optional bar) #:optional baz) '())
This illustrates currying. A procedure foo is defined, which,
when called with an optional argument bar, returns a procedure
that takes an optional argument baz.
Of course, define*[-public] also supports #:rest and
#:allow-other-keys in the same way as lambda*.
defmacro and defmacro-public except that they
take lambda*-style extended parameter lists, where #:optional,
#:key, #:allow-other-keys and #:rest are allowed with the usual
semantics. Here is an example of a macro with an optional argument:
(defmacro* transmorgify (a #:optional b)
(a 1))
Procedures always have attached the environment in which they were created and information about how to apply them to actual arguments. In addition to that, properties and meta-information can be stored with procedures. The procedures in this section can be used to test whether a given procedure satisfies a condition; and to access and set a procedure's property.
The first group of procedures are predicates to test whether a Scheme
object is a procedure, or a special procedure, respectively.
procedure? is the most general predicates, it returns #t
for any kind of procedure. closure? does not return #t
for primitive procedures, and thunk? only returns #t for
procedures which do not accept any arguments.
#t if obj is a procedure.
#t if obj is a closure.
#t if obj is a thunk.
Procedure properties are general properties to be attached to procedures. These can be the name of a procedure or other relevant information, such as debug hints.
Documentation for a procedure can be accessed with the procedure
procedure-documentation.
proc. By
convention, if a procedure contains more than one expression and the
first expression is a string constant, that string is assumed to contain
documentation for that procedure.
Source properties are properties which are related to the source code of a procedure, such as the line and column numbers, the file name etc.
A procedure with setter is a special kind of procedure which normally behaves like any accessor procedure, that is a procedure which accesses a data structure. The difference is that this kind of procedure has a so-called setter attached, which is a procedure for storing something into a data structure.
Procedures with setters are treated specially when the procedure appears
in the special form set! (REFFIXME). How it works is best shown
by example.
Suppose we have a procedure called foo-ref, which accepts two
arguments, a value of type foo and an integer. The procedure
returns the value stored at the given index in the foo object.
Let f be a variable containing such a foo data
structure.(10)
(foo-ref f 0) => bar (foo-ref f 1) => braz
Also suppose that a corresponding setter procedure called
foo-set! does exist.
(foo-set! f 0 'bla) (foo-ref f 0) => bla
Now we could create a new procedure called foo, which is a
procedure with setter, by calling make-procedure-with-setter with
the accessor and setter procedures foo-ref and foo-set!.
Let us call this new procedure foo.
(define foo (make-procedure-with-setter foo-ref foo-set!))
foo can from now an be used to either read from the data
structure stored in f, or to write into the structure.
(set! (foo f 0) 'dum) (foo f 0) => dum
#t if obj is a procedure with an
associated setter procedure.
Macros are objects which cause the expression that they appear in to be transformed in some way before being evaluated. In expressions that are intended for macro transformation, the identifier that names the relevant macro must appear as the first element, like this:
(macro-name macro-args ...)
In Lisp-like languages, the traditional way to define macros is very
similar to procedure definitions. The key differences are that the
macro definition body should return a list that describes the
transformed expression, and that the definition is marked as a macro
definition (rather than a procedure definition) by the use of a
different definition keyword: in Lisp, defmacro rather than
defun, and in Scheme, define-macro rather than
define.
Guile supports this style of macro definition using both defmacro
and define-macro. The only difference between them is how the
macro name and arguments are grouped together in the definition:
(defmacro name (args ...) body ...)
is the same as
(define-macro (name args ...) body ...)
The difference is analogous to the corresponding difference between
Lisp's defun and Scheme's define.
false-if-exception, from the `boot-9.scm' file in the Guile
distribution, is a good example of macro definition using
defmacro:
(defmacro false-if-exception (expr)
`(catch #t
(lambda () ,expr)
(lambda args #f)))
The effect of this definition is that expressions beginning with the
identifier false-if-exception are automatically transformed into
a catch expression following the macro definition specification.
For example:
(false-if-exception (open-input-file "may-not-exist"))
==
(catch #t
(lambda () (open-input-file "may-not-exist"))
(lambda args #f))
syntax-rules System
R5RS defines an alternative system for macro and syntax transformations
using the keywords define-syntax, let-syntax,
letrec-syntax and syntax-rules.
The main difference between the R5RS system and the traditional macros of the previous section is how the transformation is specified. In R5RS, rather than permitting a macro definition to return an arbitrary expression, the transformation is specified in a pattern language that
caddr etc.
The last point is commonly referred to as being hygienic: the R5RS
syntax-case system provides hygienic macros.
For example, the R5RS pattern language for the false-if-exception
example of the previous section looks like this:
(syntax-rules ()
((_ expr)
(catch #t
(lambda () expr)
(lambda args #f))))
In Guile, the syntax-rules system is provided by the (ice-9
syncase) module. To make these facilities available in your code,
include the expression (use-modules (ice-9 syncase)) or
(use-syntax (ice-9 syncase)) (see section Using Guile Modules)
before the first usage of define-syntax etc. If you are writing
a Scheme module, you can alternatively use one of the keywords
#:use-module and #:use-syntax in your define-module
declaration (see section Creating Guile Modules).
syntax-rules Pattern Languagedefine-syntax: The gist is
(define-syntax <keyword> <transformer-spec>)
makes the <keyword> into a macro so that
(<keyword> ...)
expands at _compile_ or _read_ time (i.e. before any evaluation begins) into some expression that is given by the <transformer-spec>.
syntax-case SystemInternally, Guile uses three different flavors of macros. The three flavors are called acro (or syntax), macro and mmacro.
Given the expression
(foo ...)
with foo being some flavor of macro, one of the following things
will happen when the expression is evaluated.
foo has been defined to be an acro, the procedure used
in the acro definition of foo is passed the whole expression and
the current lexical environment, and whatever that procedure returns is
the value of evaluating the expression. You can think of this a
procedure that receives its argument as an unevaluated expression.
foo has been defined to be a macro, the procedure used
in the macro definition of foo is passed the whole expression and
the current lexical environment, and whatever that procedure returns is
evaluated again. That is, the procedure should return a valid Scheme
expression.
foo has been defined to be a mmacro, the procedure
used in the mmacro definition of `foo' is passed the whole expression
and the current lexical environment, and whatever that procedure returns
replaces the original expression. Evaluation then starts over from the
new expression that has just been returned.
The key difference between a macro and a mmacro is that the expression returned by a mmacro procedure is remembered (or memoized) so that the expansion does not need to be done again next time the containing code is evaluated.
The primitives procedure->syntax, procedure->macro and
procedure->memoizing-macro are used to construct acros, macros
and mmacros respectively. However, if you do not have a very special
reason to use one of these primitives, you should avoid them: they are
very specific to Guile's current implementation and therefore likely to
change. Use defmacro, define-macro (see section Lisp Style Macro Definitions) or
define-syntax (see section The R5RS syntax-rules System) instead. (In low level
terms, defmacro, define-macro and define-syntax are
all implemented as mmacros.)
(define trace (procedure->macro (lambda (x env) `(set! ,(cadr x) (tracef ,(cadr x) ',(cadr x)))))) (trace foo) == (set! foo (tracef foo 'foo)).
procedure->memoizing-macro is the same as
procedure->macro, except that the expression returned by
code replaces the original macro expression in the memoized form
of the containing code.
In the following primitives, acro flavor macros are referred to as syntax transformers.
#t if obj is a regular macro, a memoizing macro or a
syntax transformer.
syntax, macro or
macro!, depending on whether m is a syntax
transformer, a regular macro, or a memoizing macro,
respectively. If m is not a macro, #f is
returned.
Go to the first, previous, next, last section, table of contents.