Guile Reference Manual

The Guile Reference Manual

This manual documents Guile version 3.0.4.

Copyright (C) 1996-1997, 2000-2005, 2009-2020 Free Software Foundation, Inc.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled “GNU Free Documentation License.”

Table of Contents

Preface

This manual describes how to use Guile, GNU’s Ubiquitous Intelligent Language for Extensions. It relates particularly to Guile version 3.0.4.

Contributors to this Manual

Like Guile itself, the Guile reference manual is a living entity, cared for by many people over a long period of time. As such, it is hard to identify individuals of whom to say “yes, this single person wrote the manual.”

Still, among the many contributions, some caretakers stand out. First among them is Neil Jerram, who has worked on this document for over ten years. Neil’s attention both to detail and to the big picture have made a real difference in the understanding of a generation of Guile hackers.

Next we should note Marius Vollmer’s effect on this document. Marius maintained Guile during a period in which Guile’s API was clarified—put to the fire, so to speak—and he had the good sense to effect the same change on the manual.

Martin Grabmueller made substantial contributions throughout the manual in preparation for the Guile 1.6 release, including filling out a lot of the documentation of Scheme data types, control mechanisms and procedures. In addition, he wrote the documentation for Guile’s SRFI modules and modules associated with the Guile REPL.

Ludovic Courtès and Andy Wingo, who co-maintain Guile since 2010, along with Mark Weaver, have also made their dent in the manual, writing documentation for new modules and subsystems that arrived with Guile 2.0. Ludovic, Andy, and Mark are also responsible for ensuring that the existing text retains its relevance as Guile evolves. See Reporting Bugs, for more information on reporting problems in this manual.

The content for the first versions of this manual incorporated and was inspired by documents from Aubrey Jaffer, author of the SCM system on which Guile was based, and from Tom Lord, Guile’s first maintainer. Although most of this text has been rewritten, all of it was important, and some of the structure remains.

The manual for the first versions of Guile were largely written, edited, and compiled by Mark Galassi and Jim Blandy. In particular, Jim wrote the original tutorial on Guile’s data representation and the C API for accessing Guile objects.

Significant portions were also contributed by Thien-Thi Nguyen, Kevin Ryde, Mikael Djurfeldt, Christian Lynbech, Julian Graham, Gary Houston, Tim Pierce, and a few dozen more. You, reader, are most welcome to join their esteemed ranks. Visit Guile’s web site at http://www.gnu.org/software/guile/ to find out how to get involved.

The Guile License

Guile is Free Software. Guile is copyrighted, not public domain, and there are restrictions on its distribution or redistribution, but these restrictions are designed to permit everything a cooperating person would want to do.

The Guile library (libguile) and supporting files are published under the terms of the GNU Lesser General Public License version 3 or later. See the files COPYING.LESSER and COPYING .

and . The Guile readline module is published under the terms of the GNU General Public License version 3 or later. See the file COPYING .

. The manual you’re now reading is published under the terms of the GNU Free Documentation License (see GNU Free Documentation License).

C code linking to the Guile library is subject to terms of that library. Basically such code may be published on any terms, provided users can re-link against a new or modified version of Guile.

C code linking to the Guile readline module is subject to the terms of that module. Basically such code must be published on Free terms.

Scheme level code written to be run by Guile (but not derived from Guile itself) is not restricted in any way, and may be published on any terms. We encourage authors to publish on Free terms.

You must be aware there is no warranty whatsoever for Guile. This is described in full in the licenses.

1 Introduction

Guile is an implementation of the Scheme programming language. Scheme (http://schemers.org/) is an elegant and conceptually simple dialect of Lisp, originated by Guy Steele and Gerald Sussman, and since evolved by the series of reports known as RnRS (the Revised^n Reports on Scheme).

Unlike, for example, Python or Perl, Scheme has no benevolent dictator. There are many Scheme implementations, with different characteristics and with communities and academic activities around them, and the language develops as a result of the interplay between these. Guile’s particular characteristics are that

it is easy to combine with other code written in C

it has a historical and continuing connection with the GNU Project

it emphasizes interactive and incremental programming

it actually supports several languages, not just Scheme.

The next few sections explain what we mean by these points. The sections after that cover how you can obtain and install Guile, and the typographical conventions that we use in this manual.

1.1 Guile and Scheme

Guile implements Scheme as described in the Revised^5 Report on the Algorithmic Language Scheme (usually known as R5RS ), providing clean and general data and control structures. Guile goes beyond the rather austere language presented in R5RS , extending it with a module system, full access to POSIX system calls, networking support, multiple threads, dynamic linking, a foreign function call interface, powerful string processing, and many other features needed for programming in the real world.

In 2007, the Scheme community agreed upon and published R6RS, a significant installment in the RnRS series. R6RS expands the core Scheme language, and standardises many non-core functions that implementations—including Guile—have previously done in different ways. Over time, Guile has been updated to incorporate almost all of the features of R6RS, and to adjust some existing features to conform to the R6RS specification. See R6RS Support, for full details.

In parallel to official standardization efforts, the SRFI process (http://srfi.schemers.org/) standardises interfaces for many practical needs, such as multithreaded programming and multidimensional arrays. Guile supports many SRFIs, as documented in detail in SRFI Support.

The process that led to the R6RS standard brought a split in the Scheme community to the surface. The implementors that wrote R6RS considered that it was impossible to write useful, portable programs in R5RS, and that only an ambitious standard could solve this problem. However, part of the Scheme world saw the R6RS effort as too broad, and as having included some components that would never be adopted by more minimalistic Scheme implementations. This second group succeeded in taking control of the official Scheme standardization track and in 2013 released a more limited R7RS, essentially consisting of R5RS, plus a module system. Guile supports R7RS also. See R7RS Support.

With R6RS and R7RS, the unified Scheme standardization process appears to have more or less run its course. There will continue to be more code written in terms of both systems, and modules defined using the SRFI process, and Guile will support both. However for future directions, Guile takes inspiration from other related language communities: Racket, Clojure, Concurrent ML, and so on.

In summary, Guile supports writing and running code written to the R5RS, R6RS, and R7RS Scheme standards, and also supports a number of SRFI modules. However for most users, until a need for cross-implementation portability has been identified, we recommend using the parts of Guile that are useful in solving the problem at hand, regardless of whether they proceed from a standard or whether they are Guile-specific.

1.2 Combining with C Code

Like a shell, Guile can run interactively—reading expressions from the user, evaluating them, and displaying the results—or as a script interpreter, reading and executing Scheme code from a file. Guile also provides an object library, libguile, that allows other applications to easily incorporate a complete Scheme interpreter. An application can then use Guile as an extension language, a clean and powerful configuration language, or as multi-purpose “glue”, connecting primitives provided by the application. It is easy to call Scheme code from C code and vice versa, giving the application designer full control of how and when to invoke the interpreter. Applications can add new functions, data types, control structures, and even syntax to Guile, creating a domain-specific language tailored to the task at hand, but based on a robust language design.

This kind of combination is helped by four aspects of Guile’s design and history. First is that Guile has always been targeted as an extension language. Hence its C API has always been of great importance, and has been developed accordingly. Second and third are rather technical points—that Guile uses conservative garbage collection, and that it implements the Scheme concept of continuations by copying and reinstating the C stack—but whose practical consequence is that most existing C code can be glued into Guile as is, without needing modifications to cope with strange Scheme execution flows. Last is the module system, which helps extensions to coexist without stepping on each others’ toes.

Guile’s module system allows one to break up a large program into manageable sections with well-defined interfaces between them. Modules may contain a mixture of interpreted and compiled code; Guile can use either static or dynamic linking to incorporate compiled code. Modules also encourage developers to package up useful collections of routines for general distribution; as of this writing, one can find Emacs interfaces, database access routines, compilers, GUI toolkit interfaces, and HTTP client functions, among others.

1.3 Guile and the GNU Project

Guile was conceived by the GNU Project following the fantastic success of Emacs Lisp as an extension language within Emacs. Just as Emacs Lisp allowed complete and unanticipated applications to be written within the Emacs environment, the idea was that Guile should do the same for other GNU Project applications. This remains true today.

The idea of extensibility is closely related to the GNU project’s primary goal, that of promoting software freedom. Software freedom means that people receiving a software package can modify or enhance it to their own desires, including in ways that may not have occurred at all to the software’s original developers. For programs written in a compiled language like C, this freedom covers modifying and rebuilding the C code; but if the program also provides an extension language, that is usually a much friendlier and lower-barrier-of-entry way for the user to start making their own changes.

Guile is now used by GNU project applications such as AutoGen, Lilypond, Denemo, Mailutils, TeXmacs and Gnucash, and we hope that there will be many more in future.

1.4 Interactive Programming

Non-free software has no interest in its users being able to see how it works. They are supposed to just accept it, or to report problems and hope that the source code owners will choose to work on them.

Free software aims to work reliably just as much as non-free software does, but it should also empower its users by making its workings available. This is useful for many reasons, including education, auditing and enhancements, as well as for debugging problems.

The ideal free software system achieves this by making it easy for interested users to see the source code for a feature that they are using, and to follow through that source code step-by-step, as it runs. In Emacs, good examples of this are the source code hyperlinks in the help system, and edebug . Then, for bonus points and maximising the ability for the user to experiment quickly with code changes, the system should allow parts of the source code to be modified and reloaded into the running program, to take immediate effect.

Guile is designed for this kind of interactive programming, and this distinguishes it from many Scheme implementations that instead prioritise running a fixed Scheme program as fast as possible—because there are tradeoffs between performance and the ability to modify parts of an already running program. There are faster Schemes than Guile, but Guile is a GNU project and so prioritises the GNU vision of programming freedom and experimentation.

1.5 Supporting Multiple Languages

Since the 2.0 release, Guile’s architecture supports compiling any language to its core virtual machine bytecode, and Scheme is just one of the supported languages. Other supported languages are Emacs Lisp, ECMAScript (commonly known as Javascript) and Brainfuck, and work is under discussion for Lua, Ruby and Python.

This means that users can program applications which use Guile in the language of their choice, rather than having the tastes of the application’s author imposed on them.

1.6 Obtaining and Installing Guile

Guile can be obtained from the main GNU archive site ftp://ftp.gnu.org or any of its mirrors. The file will be named guile- version .tar.gz. The current version is 3.0.4, so the file you should grab is:

ftp://ftp.gnu.org/gnu/guile/guile-3.0.4.tar.gz

To unbundle Guile use the instruction

zcat guile-3.0.4.tar.gz | tar xvf -

which will create a directory called guile-3.0.4 with all the sources. You can look at the file INSTALL for detailed instructions on how to build and install Guile, but you should be able to just do

cd guile-3.0.4 ./configure make make install

This will install the Guile executable guile , the Guile library libguile and various associated header files and support libraries. It will also install the Guile reference manual.

Since this manual frequently refers to the Scheme “standard”, also known as R5RS, or the “Revised^5 Report on the Algorithmic Language Scheme”, we have included the report in the Guile distribution; see Introduction in Revised(5) Report on the Algorithmic Language Scheme . This will also be installed in your info directory.

1.7 Organisation of this Manual

The rest of this manual is organised into the following chapters.

Chapter 2: Hello Guile! A whirlwind tour shows how Guile can be used interactively and as a script interpreter, how to link Guile into your own applications, and how to write modules of interpreted and compiled code for use with Guile. Everything introduced here is documented again and in full by the later parts of the manual. Chapter 3: Hello Scheme! For readers new to Scheme, this chapter provides an introduction to the basic ideas of the Scheme language. This material would apply to any Scheme implementation and so does not make reference to anything Guile-specific. Chapter 4: Programming in Scheme Provides an overview of programming in Scheme with Guile. It covers how to invoke the guile program from the command-line and how to write scripts in Scheme. It also introduces the extensions that Guile offers beyond standard Scheme. Chapter 5: Programming in C Provides an overview of how to use Guile in a C program. It discusses the fundamental concepts that you need to understand to access the features of Guile, such as dynamic types and the garbage collector. It explains in a tutorial like manner how to define new data types and functions for the use by Scheme programs. Chapter 6: Guile API Reference This part of the manual documents the Guile API in functionality-based groups with the Scheme and C interfaces presented side by side. Chapter 7: Guile Modules Describes some important modules, distributed as part of the Guile distribution, that extend the functionality provided by the Guile Scheme core. Chapter 8: GOOPS Describes GOOPS, an object oriented extension to Guile that provides classes, multiple inheritance and generic functions.

1.8 Typographical Conventions

In examples and procedure descriptions and all other places where the evaluation of Scheme expression is shown, we use some notation for denoting the output and evaluation results of expressions.

The symbol ‘ ⇒ ’ is used to tell which value is returned by an evaluation:

(+ 1 2) ⇒ 3

Some procedures produce some output besides returning a value. This is denoted by the symbol ‘ -| ’.

(begin (display 1) (newline) 'hooray) -| 1 ⇒ hooray

As you can see, this code prints ‘ 1 ’ (denoted by ‘ -| ’), and returns hooray (denoted by ‘ ⇒ ’).

2 Hello Guile!

This chapter presents a quick tour of all the ways that Guile can be used. There are additional examples in the examples/ directory in the Guile source distribution. It also explains how best to report any problems that you find.

The following examples assume that Guile has been installed in /usr/local/ .

2.1 Running Guile Interactively

In its simplest form, Guile acts as an interactive interpreter for the Scheme programming language, reading and evaluating Scheme expressions the user enters from the terminal. Here is a sample interaction between Guile and a user; the user’s input appears after the $ and scheme@(guile-user)> prompts:

$ guile scheme@(guile-user)> (+ 1 2 3) ; add some numbers $1 = 6 scheme@(guile-user)> (define (factorial n) ; define a function (if (zero? n) 1 (* n (factorial (- n 1))))) scheme@(guile-user)> (factorial 20) $2 = 2432902008176640000 scheme@(guile-user)> (getpwnam "root") ; look in /etc/passwd $3 = #("root" "x" 0 0 "root" "/root" "/bin/bash") scheme@(guile-user)> C-d $

2.2 Running Guile Scripts

Like AWK, Perl, or any shell, Guile can interpret script files. A Guile script is simply a file of Scheme code with some extra information at the beginning which tells the operating system how to invoke Guile, and then tells Guile how to handle the Scheme code.

Here is a trivial Guile script. See Guile Scripting, for more details.

#!/usr/local/bin/guile -s !# (display "Hello, world!") (newline)

2.3 Linking Guile into Programs

The Guile interpreter is available as an object library, to be linked into applications using Scheme as a configuration or extension language.

Here is simple-guile.c , source code for a program that will produce a complete Guile interpreter. In addition to all usual functions provided by Guile, it will also offer the function my-hostname .

#include <stdlib.h> #include <libguile.h> static SCM my_hostname (void) { char *s = getenv ("HOSTNAME"); if (s == NULL) return SCM_BOOL_F; else return scm_from_locale_string (s); } static void inner_main (void *data, int argc, char **argv) { scm_c_define_gsubr ("my-hostname", 0, 0, 0, my_hostname); scm_shell (argc, argv); } int main (int argc, char **argv) { scm_boot_guile (argc, argv, inner_main, 0); return 0; /* never reached */ }

When Guile is correctly installed on your system, the above program can be compiled and linked like this:

$ gcc -o simple-guile simple-guile.c \ `pkg-config --cflags --libs guile-3.0`

When it is run, it behaves just like the guile program except that you can also call the new my-hostname function.

$ ./simple-guile scheme@(guile-user)> (+ 1 2 3) $1 = 6 scheme@(guile-user)> (my-hostname) "burns"

2.4 Writing Guile Extensions

You can link Guile into your program and make Scheme available to the users of your program. You can also link your library into Guile and make its functionality available to all users of Guile.

A library that is linked into Guile is called an extension, but it really just is an ordinary object library.

The following example shows how to write a simple extension for Guile that makes the j0 function available to Scheme code.

#include <math.h> #include <libguile.h> SCM j0_wrapper (SCM x) { return scm_from_double (j0 (scm_to_double (x))); } void init_bessel () { scm_c_define_gsubr ("j0", 1, 0, 0, j0_wrapper); }

This C source file needs to be compiled into a shared library. Here is how to do it on GNU/Linux:

gcc `pkg-config --cflags guile-3.0` \ -shared -o libguile-bessel.so -fPIC bessel.c

For creating shared libraries portably, we recommend the use of GNU Libtool (see Introduction in GNU Libtool ).

A shared library can be loaded into a running Guile process with the function load-extension . The j0 is then immediately available:

$ guile scheme@(guile-user)> (load-extension "./libguile-bessel" "init_bessel") scheme@(guile-user)> (j0 2) $1 = 0.223890779141236

For more on how to install your extension, see Installing Site Packages.

2.5 Using the Guile Module System

Guile has support for dividing a program into modules. By using modules, you can group related code together and manage the composition of complete programs from largely independent parts.

For more details on the module system beyond this introductory material, See Modules.

2.5.1 Using Modules

Guile comes with a lot of useful modules, for example for string processing or command line parsing. Additionally, there exist many Guile modules written by other Guile hackers, but which have to be installed manually.

Here is a sample interactive session that shows how to use the (ice-9 popen) module which provides the means for communicating with other processes over pipes together with the (ice-9 rdelim) module that provides the function read-line .

$ guile scheme@(guile-user)> (use-modules (ice-9 popen)) scheme@(guile-user)> (use-modules (ice-9 rdelim)) scheme@(guile-user)> (define p (open-input-pipe "ls -l")) scheme@(guile-user)> (read-line p) $1 = "total 30" scheme@(guile-user)> (read-line p) $2 = "drwxr-sr-x 2 mgrabmue mgrabmue 1024 Mar 29 19:57 CVS"

2.5.2 Writing new Modules

You can create new modules using the syntactic form define-module . All definitions following this form until the next define-module are placed into the new module.

One module is usually placed into one file, and that file is installed in a location where Guile can automatically find it. The following session shows a simple example.

$ cat /usr/local/share/guile/site/foo/bar.scm (define-module (foo bar) #:export (frob)) (define (frob x) (* 2 x)) $ guile scheme@(guile-user)> (use-modules (foo bar)) scheme@(guile-user)> (frob 12) $1 = 24

For more on how to install your module, see Installing Site Packages.

2.5.3 Putting Extensions into Modules

In addition to Scheme code you can also put things that are defined in C into a module.

You do this by writing a small Scheme file that defines the module and call load-extension directly in the body of the module.

$ cat /usr/local/share/guile/site/math/bessel.scm (define-module (math bessel) #:export (j0)) (load-extension "libguile-bessel" "init_bessel") $ file /usr/local/lib/guile/3.0/extensions/libguile-bessel.so … ELF 32-bit LSB shared object … $ guile scheme@(guile-user)> (use-modules (math bessel)) scheme@(guile-user)> (j0 2) $1 = 0.223890779141236

See Modules and Extensions, for more information.

2.6 Reporting Bugs

Any problems with the installation should be reported to bug-guile@gnu.org.

If you find a bug in Guile, please report it to the Guile developers, so they can fix it. They may also be able to suggest workarounds when it is not possible for you to apply the bug-fix or install a new version of Guile yourself.

Before sending in bug reports, please check with the following list that you really have found a bug.

Whenever documentation and actual behavior differ, you have certainly found a bug, either in the documentation or in the program.

When Guile crashes, it is a bug.

When Guile hangs or takes forever to complete a task, it is a bug.

When calculations produce wrong results, it is a bug.

When Guile signals an error for valid Scheme programs, it is a bug.

When Guile does not signal an error for invalid Scheme programs, it may be a bug, unless this is explicitly documented.

When some part of the documentation is not clear and does not make sense to you even after re-reading the section, it is a bug.

Before reporting the bug, check whether any programs you have loaded into Guile, including your .guile file, set any variables that may affect the functioning of Guile. Also, see whether the problem happens in a freshly started Guile without loading your .guile file (start Guile with the -q switch to prevent loading the init file). If the problem does not occur then, you must report the precise contents of any programs that you must load into Guile in order to cause the problem to occur.

When you write a bug report, please make sure to include as much of the information described below in the report. If you can’t figure out some of the items, it is not a problem, but the more information we get, the more likely we can diagnose and fix the bug.

The version number of Guile. You can get this information from invoking ‘ guile --version ’ at your shell, or calling (version) from within Guile.

’ at your shell, or calling from within Guile. Your machine type, as determined by the config.guess shell script. If you have a Guile checkout, this file is located in build-aux ; otherwise you can fetch the latest version from http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD. $ build-aux/config.guess x86_64-unknown-linux-gnu

shell script. If you have a Guile checkout, this file is located in ; otherwise you can fetch the latest version from http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD. If you installed Guile from a binary package, the version of that package. On systems that use RPM, use rpm -qa | grep guile . On systems that use DPKG, dpkg -l | grep guile .

. On systems that use DPKG, . If you built Guile yourself, the build configuration that you used: $ ./config.status --config '--enable-error-on-warning' '--disable-deprecated'...

A complete description of how to reproduce the bug. If you have a Scheme program that produces the bug, please include it in the bug report. If your program is too big to include, please try to reduce your code to a minimal test case. If you can reproduce your problem at the REPL, that is best. Give a transcript of the expressions you typed at the REPL.

A description of the incorrect behavior. For example, "The Guile process gets a fatal signal," or, "The resulting output is as follows, which I think is wrong." If the manifestation of the bug is a Guile error message, it is important to report the precise text of the error message, and a backtrace showing how the Scheme program arrived at the error. This can be done using the ,backtrace command in Guile’s debugger.

If your bug causes Guile to crash, additional information from a low-level debugger such as GDB might be helpful. If you have built Guile yourself, you can run Guile under GDB via the meta/gdb-uninstalled-guile script. Instead of invoking Guile as usual, invoke the wrapper script, type run to start the process, then backtrace when the crash comes. Include that backtrace in your report.

3 Hello Scheme!

In this chapter, we introduce the basic concepts that underpin the elegance and power of the Scheme language.

Readers who already possess a background knowledge of Scheme may happily skip this chapter. For the reader who is new to the language, however, the following discussions on data, procedures, expressions and closure are designed to provide a minimum level of Scheme understanding that is more or less assumed by the chapters that follow.

The style of this introductory material aims about halfway between the terse precision of R5RS and the discursiveness of existing Scheme tutorials. For pointers to useful Scheme resources on the web, please see Further Reading.

• About Data Latent typing, types, values and variables. • About Procedures The representation and use of procedures. • About Expressions All kinds of expressions and their meaning. • About Closure Closure, scoping and environments. • Further Reading Where to find out more about Scheme.

3.1 Data Types, Values and Variables

This section discusses the representation of data types and values, what it means for Scheme to be a latently typed language, and the role of variables. We conclude by introducing the Scheme syntaxes for defining a new variable, and for changing the value of an existing variable.

• Latent Typing Scheme as a "latently typed" language. • Values and Variables About data types, values and variables. • Definition Defining variables and setting their values.

3.1.1 Latent Typing

The term latent typing is used to describe a computer language, such as Scheme, for which you cannot, in general, simply look at a program’s source code and determine what type of data will be associated with a particular variable, or with the result of a particular expression.

Sometimes, of course, you can tell from the code what the type of an expression will be. If you have a line in your program that sets the variable x to the numeric value 1, you can be certain that, immediately after that line has executed (and in the absence of multiple threads), x has the numeric value 1. Or if you write a procedure that is designed to concatenate two strings, it is likely that the rest of your application will always invoke this procedure with two string parameters, and quite probable that the procedure would go wrong in some way if it was ever invoked with parameters that were not both strings.

Nevertheless, the point is that there is nothing in Scheme which requires the procedure parameters always to be strings, or x always to hold a numeric value, and there is no way of declaring in your program that such constraints should always be obeyed. In the same vein, there is no way to declare the expected type of a procedure’s return value.

Instead, the types of variables and expressions are only known – in general – at run time. If you need to check at some point that a value has the expected type, Scheme provides run time procedures that you can invoke to do so. But equally, it can be perfectly valid for two separate invocations of the same procedure to specify arguments with different types, and to return values with different types.

The next subsection explains what this means in practice, for the ways that Scheme programs use data types, values and variables.

3.1.2 Values and Variables

Scheme provides many data types that you can use to represent your data. Primitive types include characters, strings, numbers and procedures. Compound types, which allow a group of primitive and compound values to be stored together, include lists, pairs, vectors and multi-dimensional arrays. In addition, Guile allows applications to define their own data types, with the same status as the built-in standard Scheme types.

As a Scheme program runs, values of all types pop in and out of existence. Sometimes values are stored in variables, but more commonly they pass seamlessly from being the result of one computation to being one of the parameters for the next.

Consider an example. A string value is created because the interpreter reads in a literal string from your program’s source code. Then a numeric value is created as the result of calculating the length of the string. A second numeric value is created by doubling the calculated length. Finally the program creates a list with two elements – the doubled length and the original string itself – and stores this list in a program variable.

All of the values involved here – in fact, all values in Scheme – carry their type with them. In other words, every value “knows,” at runtime, what kind of value it is. A number, a string, a list, whatever.

A variable, on the other hand, has no fixed type. A variable – x , say – is simply the name of a location – a box – in which you can store any kind of Scheme value. So the same variable in a program may hold a number at one moment, a list of procedures the next, and later a pair of strings. The “type” of a variable – insofar as the idea is meaningful at all – is simply the type of whatever value the variable happens to be storing at a particular moment.

3.1.3 Defining and Setting Variables

To define a new variable, you use Scheme’s define syntax like this:

(define variable-name value )

This makes a new variable called variable-name and stores value in it as the variable’s initial value. For example:

;; Make a variable `x' with initial numeric value 1. (define x 1) ;; Make a variable `organization' with an initial string value. (define organization "Free Software Foundation")

(In Scheme, a semicolon marks the beginning of a comment that continues until the end of the line. So the lines beginning ;; are comments.)

Changing the value of an already existing variable is very similar, except that define is replaced by the Scheme syntax set! , like this:

(set! variable-name new-value )

Remember that variables do not have fixed types, so new-value may have a completely different type from whatever was previously stored in the location named by variable-name . Both of the following examples are therefore correct.

;; Change the value of `x' to 5. (set! x 5) ;; Change the value of `organization' to the FSF's street number. (set! organization 545)

In these examples, value and new-value are literal numeric or string values. In general, however, value and new-value can be any Scheme expression. Even though we have not yet covered the forms that Scheme expressions can take (see About Expressions), you can probably guess what the following set! example does…

(set! x (+ x 1))

(Note: this is not a complete description of define and set! , because we need to introduce some other aspects of Scheme before the missing pieces can be filled in. If, however, you are already familiar with the structure of Scheme, you may like to read about those missing pieces immediately by jumping ahead to the following references.

Lambda Alternatives, to read about an alternative form of the define syntax that can be used when defining new procedures.

syntax that can be used when defining new procedures. Procedures with Setters, to read about an alternative form of the set! syntax that helps with changing a single value in the depths of a compound data structure.)

syntax that helps with changing a single value in the depths of a compound data structure.) See Internal Definitions, to read about using define other than at top level in a Scheme program, including a discussion of when it works to use define rather than set! to change the value of an existing variable.

3.2 The Representation and Use of Procedures

This section introduces the basics of using and creating Scheme procedures. It discusses the representation of procedures as just another kind of Scheme value, and shows how procedure invocation expressions are constructed. We then explain how lambda is used to create new procedures, and conclude by presenting the various shorthand forms of define that can be used instead of writing an explicit lambda expression.

• Procedures as Values Procedures are values like everything else. • Simple Invocation How to write a simple procedure invocation. • Creating a Procedure How to create your own procedures. • Lambda Alternatives Other ways of writing procedure definitions.

3.2.1 Procedures as Values

One of the great simplifications of Scheme is that a procedure is just another type of value, and that procedure values can be passed around and stored in variables in exactly the same way as, for example, strings and lists. When we talk about a built-in standard Scheme procedure such as open-input-file , what we actually mean is that there is a pre-defined top level variable called open-input-file , whose value is a procedure that implements what R5RS says that open-input-file should do.

Note that this is quite different from many dialects of Lisp — including Emacs Lisp — in which a program can use the same name with two quite separate meanings: one meaning identifies a Lisp function, while the other meaning identifies a Lisp variable, whose value need have nothing to do with the function that is associated with the first meaning. In these dialects, functions and variables are said to live in different namespaces.

In Scheme, on the other hand, all names belong to a single unified namespace, and the variables that these names identify can hold any kind of Scheme value, including procedure values.

One consequence of the “procedures as values” idea is that, if you don’t happen to like the standard name for a Scheme procedure, you can change it.

For example, call-with-current-continuation is a very important standard Scheme procedure, but it also has a very long name! So, many programmers use the following definition to assign the same procedure value to the more convenient name call/cc .

(define call/cc call-with-current-continuation)

Let’s understand exactly how this works. The definition creates a new variable call/cc , and then sets its value to the value of the variable call-with-current-continuation ; the latter value is a procedure that implements the behaviour that R5RS specifies under the name “call-with-current-continuation”. So call/cc ends up holding this value as well.

Now that call/cc holds the required procedure value, you could choose to use call-with-current-continuation for a completely different purpose, or just change its value so that you will get an error if you accidentally use call-with-current-continuation as a procedure in your program rather than call/cc . For example:

(set! call-with-current-continuation "Not a procedure any more!")

Or you could just leave call-with-current-continuation as it was. It’s perfectly fine for more than one variable to hold the same procedure value.

3.2.2 Simple Procedure Invocation

A procedure invocation in Scheme is written like this:

( procedure [ arg1 [ arg2 …]])

In this expression, procedure can be any Scheme expression whose value is a procedure. Most commonly, however, procedure is simply the name of a variable whose value is a procedure.

For example, string-append is a standard Scheme procedure whose behaviour is to concatenate together all the arguments, which are expected to be strings, that it is given. So the expression

(string-append "/home" "/" "andrew")

is a procedure invocation whose result is the string value "/home/andrew" .

Similarly, string-length is a standard Scheme procedure that returns the length of a single string argument, so

(string-length "abc")

is a procedure invocation whose result is the numeric value 3.

Each of the parameters in a procedure invocation can itself be any Scheme expression. Since a procedure invocation is itself a type of expression, we can put these two examples together to get

(string-length (string-append "/home" "/" "andrew"))

— a procedure invocation whose result is the numeric value 12.

(You may be wondering what happens if the two examples are combined the other way round. If we do this, we can make a procedure invocation expression that is syntactically correct:

(string-append "/home" (string-length "abc"))

but when this expression is executed, it will cause an error, because the result of (string-length "abc") is a numeric value, and string-append is not designed to accept a numeric value as one of its arguments.)

3.2.3 Creating and Using a New Procedure

Scheme has lots of standard procedures, and Guile provides all of these via predefined top level variables. All of these standard procedures are documented in the later chapters of this reference manual.

Before very long, though, you will want to create new procedures that encapsulate aspects of your own applications’ functionality. To do this, you can use the famous lambda syntax.

For example, the value of the following Scheme expression

(lambda (name address) body …)

is a newly created procedure that takes two arguments: name and address . The behaviour of the new procedure is determined by the sequence of expressions and definitions in the body of the procedure definition. (Typically, body would use the arguments in some way, or else there wouldn’t be any point in giving them to the procedure.) When invoked, the new procedure returns a value that is the value of the last expression in the body .

To make things more concrete, let’s suppose that the two arguments are both strings, and that the purpose of this procedure is to form a combined string that includes these arguments. Then the full lambda expression might look like this:

(lambda (name address) (string-append "Name=" name ":Address=" address))

We noted in the previous subsection that the procedure part of a procedure invocation expression can be any Scheme expression whose value is a procedure. But that’s exactly what a lambda expression is! So we can use a lambda expression directly in a procedure invocation, like this:

((lambda (name address) (string-append "Name=" name ":Address=" address)) "FSF" "Cambridge")

This is a valid procedure invocation expression, and its result is the string:

"Name=FSF:Address=Cambridge"

It is more common, though, to store the procedure value in a variable —

(define make-combined-string (lambda (name address) (string-append "Name=" name ":Address=" address)))

— and then to use the variable name in the procedure invocation:

(make-combined-string "FSF" "Cambridge")

Which has exactly the same result.

It’s important to note that procedures created using lambda have exactly the same status as the standard built in Scheme procedures, and can be invoked, passed around, and stored in variables in exactly the same ways.

3.2.4 Lambda Alternatives

Since it is so common in Scheme programs to want to create a procedure and then store it in a variable, there is an alternative form of the define syntax that allows you to do just that.

A define expression of the form

(define ( name [ arg1 [ arg2 …]]) body …)

is exactly equivalent to the longer form

(define name (lambda ([ arg1 [ arg2 …]]) body …))

So, for example, the definition of make-combined-string in the previous subsection could equally be written:

(define (make-combined-string name address) (string-append "Name=" name ":Address=" address))

This kind of procedure definition creates a procedure that requires exactly the expected number of arguments. There are two further forms of the lambda expression, which create a procedure that can accept a variable number of arguments:

(lambda ( arg1 … . args ) body …) (lambda args body …)

The corresponding forms of the alternative define syntax are:

(define ( name arg1 … . args ) body …) (define ( name . args ) body …)

For details on how these forms work, see See Lambda.

Prior to Guile 2.0, Guile provided an extension to define syntax that allowed you to nest the previous extension up to an arbitrary depth. These are no longer provided by default, and instead have been moved to Curried Definitions.

(It could be argued that the alternative define forms are rather confusing, especially for newcomers to the Scheme language, as they hide both the role of lambda and the fact that procedures are values that are stored in variables in the same way as any other kind of value. On the other hand, they are very convenient, and they are also a good example of another of Scheme’s powerful features: the ability to specify arbitrary syntactic transformations at run time, which can be applied to subsequently read input.)

3.3 Expressions and Evaluation

So far, we have met expressions that do things, such as the define expressions that create and initialize new variables, and we have also talked about expressions that have values, for example the value of the procedure invocation expression:

(string-append "/home" "/" "andrew")

but we haven’t yet been precise about what causes an expression like this procedure invocation to be reduced to its “value”, or how the processing of such expressions relates to the execution of a Scheme program as a whole.

This section clarifies what we mean by an expression’s value, by introducing the idea of evaluation. It discusses the side effects that evaluation can have, explains how each of the various types of Scheme expression is evaluated, and describes the behaviour and use of the Guile REPL as a mechanism for exploring evaluation. The section concludes with a very brief summary of Scheme’s common syntactic expressions.

• Evaluating How a Scheme program is executed. • Tail Calls Space-safe recursion. • The REPL Interacting with the Guile interpreter. • Syntax Summary Common syntactic expressions – in brief.

3.3.1 Evaluating Expressions and Executing Programs

In Scheme, the process of executing an expression is known as evaluation. Evaluation has two kinds of result:

the value of the evaluated expression

the side effects of the evaluation, which consist of any effects of evaluating the expression that are not represented by the value.

Of the expressions that we have met so far, define and set! expressions have side effects — the creation or modification of a variable — but no value; lambda expressions have values — the newly constructed procedures — but no side effects; and procedure invocation expressions, in general, have either values, or side effects, or both.

It is tempting to try to define more intuitively what we mean by “value” and “side effects”, and what the difference between them is. In general, though, this is extremely difficult. It is also unnecessary; instead, we can quite happily define the behaviour of a Scheme program by specifying how Scheme executes a program as a whole, and then by describing the value and side effects of evaluation for each type of expression individually.

So, some1 definitions…

A Scheme program consists of a sequence of expressions.

A Scheme interpreter executes the program by evaluating these expressions in order, one by one.

An expression can be a piece of literal data, such as a number 2.3 or a string "Hello world!" a variable name a procedure invocation expression one of Scheme’s special syntactic expressions.



The following subsections describe how each of these types of expression is evaluated.

3.3.1.1 Evaluating Literal Data

When a literal data expression is evaluated, the value of the expression is simply the value that the expression describes. The evaluation of a literal data expression has no side effects.

So, for example,

the value of the expression "abc" is the string value "abc"

is the string value the value of the expression 3+4i is the complex number 3 + 4i

is the complex number 3 + 4i the value of the expression #(1 2 3) is a three-element vector containing the numeric values 1, 2 and 3.

For any data type which can be expressed literally like this, the syntax of the literal data expression for that data type — in other words, what you need to write in your code to indicate a literal value of that type — is known as the data type’s read syntax. This manual specifies the read syntax for each such data type in the section that describes that data type.

Some data types do not have a read syntax. Procedures, for example, cannot be expressed as literal data; they must be created using a lambda expression (see Creating a Procedure) or implicitly using the shorthand form of define (see Lambda Alternatives).

3.3.1.2 Evaluating a Variable Reference

When an expression that consists simply of a variable name is evaluated, the value of the expression is the value of the named variable. The evaluation of a variable reference expression has no side effects.

So, after

(define key "Paul Evans")

the value of the expression key is the string value "Paul Evans" . If key is then modified by

(set! key 3.74)

the value of the expression key is the numeric value 3.74.

If there is no variable with the specified name, evaluation of the variable reference expression signals an error.

3.3.1.3 Evaluating a Procedure Invocation Expression

This is where evaluation starts getting interesting! As already noted, a procedure invocation expression has the form

( procedure [ arg1 [ arg2 …]])

where procedure must be an expression whose value, when evaluated, is a procedure.

The evaluation of a procedure invocation expression like this proceeds by

evaluating individually the expressions procedure , arg1 , arg2 , and so on

, , , and so on calling the procedure that is the value of the procedure expression with the list of values obtained from the evaluations of arg1 , arg2 etc. as its parameters.

For a procedure defined in Scheme, “calling the procedure with the list of values as its parameters” means binding the values to the procedure’s formal parameters and then evaluating the sequence of expressions that make up the body of the procedure definition. The value of the procedure invocation expression is the value of the last evaluated expression in the procedure body. The side effects of calling the procedure are the combination of the side effects of the sequence of evaluations of expressions in the procedure body.

For a built-in procedure, the value and side-effects of calling the procedure are best described by that procedure’s documentation.

Note that the complete side effects of evaluating a procedure invocation expression consist not only of the side effects of the procedure call, but also of any side effects of the preceding evaluation of the expressions procedure , arg1 , arg2 , and so on.

To illustrate this, let’s look again at the procedure invocation expression:

(string-length (string-append "/home" "/" "andrew"))

In the outermost expression, procedure is string-length and arg1 is (string-append "/home" "/" "andrew") .

Evaluation of string-length , which is a variable, gives a procedure value that implements the expected behaviour for “string-length”.

, which is a variable, gives a procedure value that implements the expected behaviour for “string-length”. Evaluation of (string-append "/home" "/" "andrew") , which is another procedure invocation expression, means evaluating each of string-append , which gives a procedure value that implements the expected behaviour for “string-append” "/home" , which gives the string value "/home" "/" , which gives the string value "/" "andrew" , which gives the string value "andrew" and then invoking the procedure value with this list of string values as its arguments. The resulting value is a single string value that is the concatenation of all the arguments, namely "/home/andrew" .

, which is another procedure invocation expression, means evaluating each of

In the evaluation of the outermost expression, the interpreter can now invoke the procedure value obtained from procedure with the value obtained from arg1 as its arguments. The resulting value is a numeric value that is the length of the argument string, which is 12.

3.3.1.4 Evaluating Special Syntactic Expressions

When a procedure invocation expression is evaluated, the procedure and all the argument expressions must be evaluated before the procedure can be invoked. Special syntactic expressions are special because they are able to manipulate their arguments in an unevaluated form, and can choose whether to evaluate any or all of the argument expressions.

Why is this needed? Consider a program fragment that asks the user whether or not to delete a file, and then deletes the file if the user answers yes.

(if (string=? (read-answer "Should I delete this file?") "yes") (delete-file file))

If the outermost (if …) expression here was a procedure invocation expression, the expression (delete-file file) , whose side effect is to actually delete a file, would already have been evaluated before the if procedure even got invoked! Clearly this is no use — the whole point of an if expression is that the consequent expression is only evaluated if the condition of the if expression is “true”.

Therefore if must be special syntax, not a procedure. Other special syntaxes that we have already met are define , set! and lambda . define and set! are syntax because they need to know the variable name that is given as the first argument in a define or set! expression, not that variable’s value. lambda is syntax because it does not immediately evaluate the expressions that define the procedure body; instead it creates a procedure object that incorporates these expressions so that they can be evaluated in the future, when that procedure is invoked.

The rules for evaluating each special syntactic expression are specified individually for each special syntax. For a summary of standard special syntax, see See Syntax Summary.

3.3.2 Tail calls

Scheme is “properly tail recursive”, meaning that tail calls or recursions from certain contexts do not consume stack space or other resources and can therefore be used on arbitrarily large data or for an arbitrarily long calculation. Consider for example,

(define (foo n) (display n) (newline) (foo (1+ n))) (foo 1) -| 1 2 3 …

foo prints numbers infinitely, starting from the given n . It’s implemented by printing n then recursing to itself to print n +1 and so on. This recursion is a tail call, it’s the last thing done, and in Scheme such tail calls can be made without limit.

Or consider a case where a value is returned, a version of the SRFI-1 last function (see SRFI-1 Selectors) returning the last element of a list,

(define (my-last lst) (if (null? (cdr lst)) (car lst) (my-last (cdr lst)))) (my-last '(1 2 3)) ⇒ 3

If the list has more than one element, my-last applies itself to the cdr . This recursion is a tail call, there’s no code after it, and the return value is the return value from that call. In Scheme this can be used on an arbitrarily long list argument.

A proper tail call is only available from certain contexts, namely the following special form positions,

and — last expression

— last expression begin — last expression

— last expression case — last expression in each clause

— last expression in each clause cond — last expression in each clause, and the call to a => procedure is a tail call

— last expression in each clause, and the call to a procedure is a tail call do — last result expression

— last result expression if — “true” and “false” leg expressions

— “true” and “false” leg expressions lambda — last expression in body

— last expression in body let , let* , letrec , let-syntax , letrec-syntax — last expression in body

, , , , — last expression in body or — last expression

The following core functions make tail calls,

apply — tail call to given procedure

— tail call to given procedure call-with-current-continuation — tail call to the procedure receiving the new continuation

— tail call to the procedure receiving the new continuation call-with-values — tail call to the values-receiving procedure

— tail call to the values-receiving procedure eval — tail call to evaluate the form

— tail call to evaluate the form string-any , string-every — tail call to predicate on the last character (if that point is reached)

The above are just core functions and special forms. Tail calls in other modules are described with the relevant documentation, for example SRFI-1 any and every (see SRFI-1 Searching).

It will be noted there are a lot of places which could potentially be tail calls, for instance the last call in a for-each , but only those explicitly described are guaranteed.

3.3.3 Using the Guile REPL

If you start Guile without specifying a particular program for it to execute, Guile enters its standard Read Evaluate Print Loop — or REPL for short. In this mode, Guile repeatedly reads in the next Scheme expression that the user types, evaluates it, and prints the resulting value.

The REPL is a useful mechanism for exploring the evaluation behaviour described in the previous subsection. If you type string-append , for example, the REPL replies #<primitive-procedure string-append> , illustrating the relationship between the variable string-append and the procedure value stored in that variable.

In this manual, the notation ⇒ is used to mean “evaluates to”. Wherever you see an example of the form

expression ⇒ result

feel free to try it out yourself by typing expression into the REPL and checking that it gives the expected result .

3.3.4 Summary of Common Syntax

This subsection lists the most commonly used Scheme syntactic expressions, simply so that you will recognize common special syntax when you see it. For a full description of each of these syntaxes, follow the appropriate reference.

lambda (see Lambda) is used to construct procedure objects.

define (see Top Level) is used to create a new variable and set its initial value.

set! (see Top Level) is used to modify an existing variable’s value.

let , let* and letrec (see Local Bindings) create an inner lexical environment for the evaluation of a sequence of expressions, in which a specified set of local variables is bound to the values of a corresponding set of expressions. For an introduction to environments, see See About Closure.

begin (see begin) executes a sequence of expressions in order and returns the value of the last expression. Note that this is not the same as a procedure which returns its last argument, because the evaluation of a procedure invocation expression does not guarantee to evaluate the arguments in order.

if and cond (see Conditionals) provide conditional evaluation of argument expressions depending on whether one or more conditions evaluate to “true” or “false”.

case (see Conditionals) provides conditional evaluation of argument expressions depending on whether a variable has one of a specified group of values.

and (see and or) executes a sequence of expressions in order until either there are no expressions left, or one of them evaluates to “false”.

or (see and or) executes a sequence of expressions in order until either there are no expressions left, or one of them evaluates to “true”.

3.4 The Concept of Closure

The concept of closure is the idea that a lambda expression “captures” the variable bindings that are in lexical scope at the point where the lambda expression occurs. The procedure created by the lambda expression can refer to and mutate the captured bindings, and the values of those bindings persist between procedure calls.

This section explains and explores the various parts of this idea in more detail.

3.4.1 Names, Locations, Values and Environments

We said earlier that a variable name in a Scheme program is associated with a location in which any kind of Scheme value may be stored. (Incidentally, the term “vcell” is often used in Lisp and Scheme circles as an alternative to “location”.) Thus part of what we mean when we talk about “creating a variable” is in fact establishing an association between a name, or identifier, that is used by the Scheme program code, and the variable location to which that name refers. Although the value that is stored in that location may change, the location to which a given name refers is always the same.

We can illustrate this by breaking down the operation of the define syntax into three parts: define

creates a new location

establishes an association between that location and the name specified as the first argument of the define expression

expression stores in that location the value obtained by evaluating the second argument of the define expression.

A collection of associations between names and locations is called an environment. When you create a top level variable in a program using define , the name-location association for that variable is added to the “top level” environment. The “top level” environment also includes name-location associations for all the procedures that are supplied by standard Scheme.

It is also possible to create environments other than the top level one, and to create variable bindings, or name-location associations, in those environments. This ability is a key ingredient in the concept of closure; the next subsection shows how it is done.

3.4.2 Local Variables and Environments

We have seen how to create top level variables using the define syntax (see Definition). It is often useful to create variables that are more limited in their scope, typically as part of a procedure body. In Scheme, this is done using the let syntax, or one of its modified forms let* and letrec . These syntaxes are described in full later in the manual (see Local Bindings). Here our purpose is to illustrate their use just enough that we can see how local variables work.

For example, the following code uses a local variable s to simplify the computation of the area of a triangle given the lengths of its three sides.

(define a 5.3) (define b 4.7) (define c 2.8) (define area (let ((s (/ (+ a b c) 2))) (sqrt (* s (- s a) (- s b) (- s c)))))

The effect of the let expression is to create a new environment and, within this environment, an association between the name s and a new location whose initial value is obtained by evaluating (/ (+ a b c) 2) . The expressions in the body of the let , namely (sqrt (* s (- s a) (- s b) (- s c))) , are then evaluated in the context of the new environment, and the value of the last expression evaluated becomes the value of the whole let expression, and therefore the value of the variable area .

3.4.3 Environment Chaining

In the example of the previous subsection, we glossed over an important point. The body of the let expression in that example refers not only to the local variable s , but also to the top level variables a , b , c and sqrt . ( sqrt is the standard Scheme procedure for calculating a square root.) If the body of the let expression is evaluated in the context of the local let environment, how does the evaluation get at the values of these top level variables?

The answer is that the local environment created by a let expression automatically has a reference to its containing environment — in this case the top level environment — and that the Scheme interpreter automatically looks for a variable binding in the containing environment if it doesn’t find one in the local environment. More generally, every environment except for the top level one has a reference to its containing environment, and the interpreter keeps searching back up the chain of environments — from most local to top level — until it either finds a variable binding for the required identifier or exhausts the chain.

This description also determines what happens when there is more than one variable binding with the same name. Suppose, continuing the example of the previous subsection, that there was also a pre-existing top level variable s created by the expression:

(define s "Some beans, my lord!")

Then both the top level environment and the local let environment would contain bindings for the name s . When evaluating code within the let body, the interpreter looks first in the local let environment, and so finds the binding for s created by the let syntax. Even though this environment has a reference to the top level environment, which also has a binding for s , the interpreter doesn’t get as far as looking there. When evaluating code outside the let body, the interpreter looks up variable names in the top level environment, so the name s refers to the top level variable.

Within the let body, the binding for s in the local environment is said to shadow the binding for s in the top level environment.

3.4.4 Lexical Scope

The rules that we have just been describing are the details of how Scheme implements “lexical scoping”. This subsection takes a brief diversion to explain what lexical scope means in general and to present an example of non-lexical scoping.

“Lexical scope” in general is the idea that

an identifier at a particular place in a program always refers to the same variable location — where “always” means “every time that the containing expression is executed”, and that

the variable location to which it refers can be determined by static examination of the source code context in which that identifier appears, without having to consider the flow of execution through the program as a whole.

In practice, lexical scoping is the norm for most programming languages, and probably corresponds to what you would intuitively consider to be “normal”. You may even be wondering how the situation could possibly — and usefully — be otherwise. To demonstrate that another kind of scoping is possible, therefore, and to compare it against lexical scoping, the following subsection presents an example of non-lexical scoping and examines in detail how its behavior differs from the corresponding lexically scoped code.

• Scoping Example An example of non-lexical scoping.

3.4.4.1 An Example of Non-Lexical Scoping

To demonstrate that non-lexical scoping does exist and can be useful, we present the following example from Emacs Lisp, which is a “dynamically scoped” language.

(defvar currency-abbreviation "USD") (defun currency-string (units hundredths) (concat currency-abbreviation (number-to-string units) "." (number-to-string hundredths))) (defun french-currency-string (units hundredths) (let ((currency-abbreviation "FRF")) (currency-string units hundredths)))

The question to focus on here is: what does the identifier currency-abbreviation refer to in the currency-string function? The answer, in Emacs Lisp, is that all variable bindings go onto a single stack, and that currency-abbreviation refers to the topmost binding from that stack which has the name “currency-abbreviation”. The binding that is created by the defvar form, to the value "USD" , is only relevant if none of the code that calls currency-string rebinds the name “currency-abbreviation” in the meanwhile.

The second function french-currency-string works precisely by taking advantage of this behaviour. It creates a new binding for the name “currency-abbreviation” which overrides the one established by the defvar form.

;; Note! This is Emacs Lisp evaluation, not Scheme! (french-currency-string 33 44) ⇒ "FRF33.44"

Now let’s look at the corresponding, lexically scoped Scheme code:

(define currency-abbreviation "USD") (define (currency-string units hundredths) (string-append currency-abbreviation (number->string units) "." (number->string hundredths))) (define (french-currency-string units hundredths) (let ((currency-abbreviation "FRF")) (currency-string units hundredths)))

According to the rules of lexical scoping, the currency-abbreviation in currency-string refers to the variable location in the innermost environment at that point in the code which has a binding for currency-abbreviation , which is the variable location in the top level environment created by the preceding (define currency-abbreviation …) expression.

In Scheme, therefore, the french-currency-string procedure does not work as intended. The variable binding that it creates for “currency-abbreviation” is purely local to the code that forms the body of the let expression. Since this code doesn’t directly use the name “currency-abbreviation” at all, the binding is pointless.

(french-currency-string 33 44) ⇒ "USD33.44"

This begs the question of how the Emacs Lisp behaviour can be implemented in Scheme. In general, this is a design question whose answer depends upon the problem that is being addressed. In this case, the best answer may be that currency-string should be redesigned so that it can take an optional third argument. This third argument, if supplied, is interpreted as a currency abbreviation that overrides the default.

It is possible to change french-currency-string so that it mostly works without changing currency-string , but the fix is inelegant, and susceptible to interrupts that could leave the currency-abbreviation variable in the wrong state:

(define (french-currency-string units hundredths) (set! currency-abbreviation "FRF") (let ((result (currency-string units hundredths))) (set! currency-abbreviation "USD") result))

The key point here is that the code does not create any local binding for the identifier currency-abbreviation , so all occurrences of this identifier refer to the top level variable.

3.4.5 Closure

Consider a let expression that doesn’t contain any lambda s:

(let ((s (/ (+ a b c) 2))) (sqrt (* s (- s a) (- s b) (- s c))))

When the Scheme interpreter evaluates this, it

creates a new environment with a reference to the environment that was current when it encountered the let

creates a variable binding for s in the new environment, with value given by (/ (+ a b c) 2)

in the new environment, with value given by evaluates the expression in the body of the let in the context of the new local environment, and remembers the value V

in the context of the new local environment, and remembers the value forgets the local environment

continues evaluating the expression that contained the let , using the value V as the value of the let expression, in the context of the containing environment.

After the let expression has been evaluated, the local environment that was created is simply forgotten, and there is no longer any way to access the binding that was created in this environment. If the same code is evaluated again, it will follow the same steps again, creating a second new local environment that has no connection with the first, and then forgetting this one as well.

If the let body contains a lambda expression, however, the local environment is not forgotten. Instead, it becomes associated with the procedure that is created by the lambda expression, and is reinstated every time that that procedure is called. In detail, this works as follows.

When the Scheme interpreter evaluates a lambda expression, to create a procedure object, it stores the current environment as part of the procedure definition.

expression, to create a procedure object, it stores the current environment as part of the procedure definition. Then, whenever that procedure is called, the interpreter reinstates the environment that is stored in the procedure definition and evaluates the procedure body within the context of that environment.

The result is that the procedure body is always evaluated in the context of the environment that was current when the procedure was created.

This is what is meant by closure. The next few subsections present examples that explore the usefulness of this concept.

3.4.6 Example 1: A Serial Number Generator

This example uses closure to create a procedure with a variable binding that is private to the procedure, like a local variable, but whose value persists between procedure calls.

(define (make-serial-number-generator) (let ((current-serial-number 0)) (lambda () (set! current-serial-number (+ current-serial-number 1)) current-serial-number))) (define entry-sn-generator (make-serial-number-generator)) (entry-sn-generator) ⇒ 1 (entry-sn-generator) ⇒ 2

When make-serial-number-generator is called, it creates a local environment with a binding for current-serial-number whose initial value is 0, then, within this environment, creates a procedure. The local environment is stored within the created procedure object and so persists for the lifetime of the created procedure.

Every time the created procedure is invoked, it increments the value of the current-serial-number binding in the captured environment and then returns the current value.

Note that make-serial-number-generator can be called again to create a second serial number generator that is independent of the first. Every new invocation of make-serial-number-generator creates a new local let environment and returns a new procedure object with an association to this environment.

3.4.7 Example 2: A Shared Persistent Variable

This example uses closure to create two procedures, get-balance and deposit , that both refer to the same captured local environment so that they can both access the balance variable binding inside that environment. The value of this variable binding persists between calls to either procedure.

Note that the captured balance variable binding is private to these two procedures: it is not directly accessible to any other code. It can only be accessed indirectly via get-balance or deposit , as illustrated by the withdraw procedure.

(define get-balance #f) (define deposit #f) (let ((balance 0)) (set! get-balance (lambda () balance)) (set! deposit (lambda (amount) (set! balance (+ balance amount)) balance))) (define (withdraw amount) (deposit (- amount))) (get-balance) ⇒ 0 (deposit 50) ⇒ 50 (withdraw 75) ⇒ -25

An important detail here is that the get-balance and deposit variables must be set up by define ing them at top level and then set! ing their values inside the let body. Using define within the let body would not work: this would create variable bindings within the local let environment that would not be accessible at top level.

3.4.8 Example 3: The Callback Closure Problem

A frequently used programming model for library code is to allow an application to register a callback function for the library to call when some particular event occurs. It is often useful for the application to make several such registrations using the same callback function, for example if several similar library events can be handled using the same application code, but the need then arises to distinguish the callback function calls that are associated with one callback registration from those that are associated with different callback registrations.

In languages without the ability to create functions dynamically, this problem is usually solved by passing a user_data parameter on the registration call, and including the value of this parameter as one of the parameters on the callback function. Here is an example of declarations using this solution in C:

typedef void (event_handler_t) (int event_type, void *user_data); void register_callback (int event_type, event_handler_t *handler, void *user_data);

In Scheme, closure can be used to achieve the same functionality without requiring the library code to store a user-data for each callback registration.

;; In the library: (define (register-callback event-type handler-proc) …) ;; In the application: (define (make-handler event-type user-data) (lambda () … <code referencing event-type and user-data> …)) (register-callback event-type (make-handler event-type …))

As far as the library is concerned, handler-proc is a procedure with no arguments, and all the library has to do is call it when the appropriate event occurs. From the application’s point of view, though, the handler procedure has used closure to capture an environment that includes all the context that the handler code needs — event-type and user-data — to handle the event correctly.

3.4.9 Example 4: Object Orientation

Closure is the capture of an environment, containing persistent variable bindings, within the definition of a procedure or a set of related procedures. This is rather similar to the idea in some object oriented languages of encapsulating a set of related data variables inside an “object”, together with a set of “methods” that operate on the encapsulated data. The following example shows how closure can be used to emulate the ideas of objects, methods and encapsulation in Scheme.

(define (make-account) (let ((balance 0)) (define (get-balance) balance) (define (deposit amount) (set! balance (+ balance amount)) balance) (define (withdraw amount) (deposit (- amount))) (lambda args (apply (case (car args) ((get-balance) get-balance) ((deposit) deposit) ((withdraw) withdraw) (else (error "Invalid method!"))) (cdr args)))))

Each call to make-account creates and returns a new procedure, created by the expression in the example code that begins “(lambda args”.

(define my-account (make-account)) my-account ⇒ #<procedure args>

This procedure acts as an account object with methods get-balance , deposit and withdraw . To apply one of the methods to the account, you call the procedure with a symbol indicating the required method as the first parameter, followed by any other parameters that are required by that method.

(my-account 'get-balance) ⇒ 0 (my-account 'withdraw 5) ⇒ -5 (my-account 'deposit 396) ⇒ 391 (my-account 'get-balance) ⇒ 391

Note how, in this example, both the current balance and the helper procedures get-balance , deposit and withdraw , used to implement the guts of the account object’s methods, are all stored in variable bindings within the private local environment captured by the lambda expression that creates the account object procedure.

3.5 Further Reading

The website http://www.schemers.org/ is a good starting point for all things Scheme.

Dorai Sitaram’s online Scheme tutorial, Teach Yourself Scheme in Fixnum Days, at http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html. Includes a nice explanation of continuations.

The complete text of Structure and Interpretation of Computer Programs, the classic introduction to computer science and Scheme by Hal Abelson, Jerry Sussman and Julie Sussman, is now available online at http://mitpress.mit.edu/sicp/sicp.html. This site also provides teaching materials related to the book, and all the source code used in the book, in a form suitable for loading and running.

4 Programming in Scheme

Guile’s core language is Scheme, and a lot can be achieved simply by using Guile to write and run Scheme programs — as opposed to having to dive into C code. In this part of the manual, we explain how to use Guile in this mode, and describe the tools that Guile provides to help you with script writing, debugging, and packaging your programs for distribution.

For detailed reference information on the variables, functions, and so on that make up Guile’s application programming interface (API), see API Reference.

4.1 Guile’s Implementation of Scheme

Guile’s core language is Scheme, which is specified and described in the series of reports known as RnRS. RnRS is shorthand for the Revised^n Report on the Algorithmic Language Scheme. Guile complies fully with R5RS (see Introduction in R5RS ), and is largely compliant with R6RS and R7RS.

Guile also has many extensions that go beyond these reports. Some of the areas where Guile extends standard Scheme are:

Guile’s interactive documentation system

Guile’s support for POSIX-compliant network programming

GOOPS – Guile’s framework for object oriented programming.

4.2 Invoking Guile

Many features of Guile depend on and can be changed by information that the user provides either before or when Guile is started. Below is a description of what information to provide and how to provide it.

• Command-line Options Command-line options understood by Guile. • Environment Variables Variables that affect Guile’s behavior.

4.2.1 Command-line Options

Here we describe Guile’s command-line processing in detail. Guile processes its arguments from left to right, recognizing the switches described below. For examples, see Scripting Examples.

script arg... -s script arg... By default, Guile will read a file named on the command line as a script. Any command-line arguments arg... following script become the script’s arguments; the command-line function returns a list of strings of the form ( script arg... ) . It is possible to name a file using a leading hyphen, for example, -myfile.scm . In this case, the file name must be preceded by -s to tell Guile that a (script) file is being named. Scripts are read and evaluated as Scheme source code just as the load function would. After loading script , Guile exits. -c expr arg... Evaluate expr as Scheme code, and then exit. Any command-line arguments arg... following expr become command-line arguments; the command-line function returns a list of strings of the form ( guile arg... ) , where guile is the path of the Guile executable. -- arg... Run interactively, prompting the user for expressions and evaluating them. Any command-line arguments arg... following the -- become command-line arguments for the interactive session; the command-line function returns a list of strings of the form ( guile arg... ) , where guile is the path of the Guile executable. -L directory Add directory to the front of Guile’s module load path. The given directories are searched in the order given on the command line and before any directories in the GUILE_LOAD_PATH environment variable. Paths added here are not in effect during execution of the user’s .guile file. -C directory Like -L , but adjusts the load path for compiled files. -x extension Add extension to the front of Guile’s load extension list (see %load-extensions ). The specified extensions are tried in the order given on the command line, and before the default load extensions. Extensions added here are not in effect during execution of the user’s .guile file. -l file Load Scheme source code from file , and continue processing the command line. -e function Make function the entry point of the script. After loading the script file (with -s ) or evaluating the expression (with -c ), apply function to a list containing the program name and the command-line arguments—the list provided by the command-line function. A -e switch can appear anywhere in the argument list, but Guile always invokes the function as the last action it performs. This is weird, but because of the way script invocation works under POSIX, the -s option must always come last in the list. The function is most often a simple symbol that names a function that is defined in the script. It can also be of the form (@ module-name symbol ) , and in that case, the symbol is looked up in the module named module-name . As a shorthand you can use the form (symbol ...) , that is, a list of only symbols that doesn’t start with @ . It is equivalent to (@ module-name main) , where module-name is (symbol ...) form. See Using Guile Modules and Scripting Examples. -ds Treat a final -s option as if it occurred at this point in the command line; load the script here. This switch is necessary because, although the POSIX script invocation mechanism effectively requires the -s option to appear last, the programmer may well want to run the script before other actions requested on the command line. For examples, see Scripting Examples. \ Read more command-line arguments, starting from the second line of the script file. See The Meta Switch. --use-srfi= list The option --use-srfi expects a comma-separated list of numbers, each representing a SRFI module to be loaded into the interpreter before evaluating a script file or starting the REPL. Additionally, the feature identifier for the loaded SRFIs is recognized by the procedure cond-expand when this option is used. Here is an example that loads the modules SRFI-8 (’receive’) and SRFI-13 (’string library’) before the GUILE interpreter is started: guile --use-srfi=8,13 --r6rs Adapt Guile’s initial environment to better support R6RS. See R6RS Incompatibilities, for some caveats. --r7rs Adapt Guile’s initial environment to better support R7RS. See R7RS Incompatibilities, for some caveats. --debug Start with the debugging virtual machine (VM) engine. Using the debugging VM will enable support for VM hooks, which are needed for tracing, breakpoints, and accurate call counts when profiling. The debugging VM is slower than the regular VM, though, by about ten percent. See VM Hooks, for more information. By default, the debugging VM engine is only used when entering an interactive session. When executing a script with -s or -c , the normal, faster VM is used by default. --no-debug Do not use the debugging VM engine, even when entering an interactive session. Note that, despite the name, Guile running with --no-debug does support the usual debugging facilities, such as printing a detailed backtrace upon error. The only difference with --debug is lack of support for VM hooks and the facilities that build upon it (see above). -q Do not load the initialization file, .guile . This option only has an effect when running interactively; running scripts does not load the .guile file. See Init File. --listen[= p ] While this program runs, listen on a local port or a path for REPL clients. If p starts with a number, it is assumed to be a local port on which to listen. If it starts with a forward slash, it is assumed to be the file name of a UNIX domain socket on which to listen. If p is not given, the default is local port 37146. If you look at it upside down, it almost spells “Guile”. If you have netcat installed, you should be able to nc localhost 37146 and get a Guile prompt. Alternately you can fire up Emacs and connect to the process; see Using Guile in Emacs for more details. Note: Opening a port allows anyone who can connect to that port to do anything Guile can do, as the user that the Guile process is running as. Do not use --listen on multi-user machines. Of course, if you do not pass --listen to Guile, no port will be opened. Guile protects against the HTTP inter-protocol exploitation attack, a scenario whereby an attacker can, via an HTML page, cause a web browser to send data to TCP servers listening on a loopback interface or private network. Nevertheless, you are advised to use UNIX domain sockets, as in --listen=/some/local/file , whenever possible. That said, --listen is great for interactive debugging and development. --auto-compile Compile source files automatically (default behavior). --fresh-auto-compile Treat the auto-compilation cache as invalid, forcing recompilation. --no-auto-compile Disable automatic source file compilation. --language= lang For the remainder of the command line arguments, assume that files mentioned with -l and expressions passed with -c are written in lang . lang must be the name of one of the languages supported by the compiler (see Compiler Tower). When run interactively, set the REPL’s language to lang (see Using Guile Interactively). The default language is scheme ; other interesting values include elisp (for Emacs Lisp), and ecmascript . The example below shows the evaluation of expressions in Scheme, Emacs Lisp, and ECMAScript: guile -c "(apply + '(1 2))" guile --language=elisp -c "(= (funcall (symbol-function '+) 1 2) 3)" guile --language=ecmascript -c '(function (x) { return x * x; })(2);' To load a file written in Scheme and one written in Emacs Lisp, and then start a Scheme REPL, type: guile -l foo.scm --language=elisp -l foo.el --language=scheme -h , --help Display help on invoking Guile, and then exit. -v , --version Display the current version of Guile, and then exit.

4.2.2 Environment Variables

The environment is a feature of the operating system; it consists of a collection of variables with names and values. Each variable is called an environment variable (or, sometimes, a “shell variable”); environment variable names are case-sensitive, and it is conventional to use upper-case letters only. The values are all text strings, even those that are written as numerals. (Note that here we are referring to names and values that are defined in the operating system shell from which Guile is invoked. This is not the same as a Scheme environment that is defined within a running instance of Guile. For a description of Scheme environments, see About Environments.)

How to set environment variables before starting Guile depends on the operating system and, especially, the shell that you are using. For example, here is how to tell Guile to provide detailed warning messages about deprecated features by setting GUILE_WARN_DEPRECATED using Bash:

$ export GUILE_WARN_DEPRECATED="detailed" $ guile

Or, detailed warnings can be turned on for a single invocation using:

$ env GUILE_WARN_DEPRECATED="detailed" guile

If you wish to retrieve or change the value of the shell environment variables that affect the run-time behavior of Guile from within a running instance of Guile, see Runtime Environment.

Here are the environment variables that affect the run-time behavior of Guile:

GUILE_AUTO_COMPILE This is a flag that can be used to tell Guile whether or not to compile Scheme source files automatically. Starting with Guile 2.0, Scheme source files will be compiled automatically, by default. If a compiled ( .go ) file corresponding to a .scm file is not found or is not newer than the .scm file, the .scm file will be compiled on the fly, and the resulting .go file stored away. An advisory note will be printed on the console. Compiled files will be stored in the directory $XDG_CACHE_HOME/guile/ccache , where XDG_CACHE_HOME defaults to the directory $HOME/.cache . This directory will be created if it does not already exist. Note that this mechanism depends on the timestamp of the .go file being newer than that of the .scm file; if the .scm or .go files are moved after installation, care should be taken to preserve their original timestamps. Set GUILE_AUTO_COMPILE to zero (0), to prevent Scheme files from being compiled automatically. Set this variable to “fresh” to tell Guile to compile Scheme files whether they are newer than the compiled files or not. See Compilation. GUILE_HISTORY This variable names the file that holds the Guile REPL command history. You can specify a different history file by setting this environment variable. By default, the history file is $HOME/.guile_history . GUILE_INSTALL_LOCALE This is a flag that can be used to tell Guile whether or not to install the current locale at startup, via a call to (setlocale LC_ALL "") 2. See Locales, for more information on locales. You may explicitly indicate that you do not want to install the locale by setting GUILE_INSTALL_LOCALE to 0 , or explicitly enable it by setting the variable to 1 . Usually, installing the current locale is the right thing to do. It allows Guile to correctly parse and print strings with non-ASCII characters. Therefore, this option is on by default. GUILE_LOAD_COMPILED_PATH This variable may be used to augment the path that is searched for compiled Scheme files ( .go files) when loading. Its value should be a colon-separated list of directories. If it contains the special path component ... (ellipsis), then the default path is put in place of the ellipsis, otherwise the default path is placed at the end. The result is stored in %load-compiled-path (see Load Paths). Here is an example using the Bash shell that adds the current directory, . , and the relative directory ../my-library to %load-compiled-path : $ export GUILE_LOAD_COMPILED_PATH=".:../my-library" $ guile -c '(display %load-compiled-path) (newline)' (. ../my-library /usr/local/lib/guile/3.0/ccache) GUILE_LOAD_PATH This variable may be used to augment the path that is searched for Scheme files when loading. Its value should be a colon-separated list of directories. If it contains the special path component ... (ellipsis), then the default path is put in place of the ellipsis, otherwise the default path is placed at the end. The result is stored in %load-path (see Load Paths). Here is an example using the Bash shell that prepends the current directory to %load-path , and adds the relative directory ../srfi to the end: $ env GUILE_LOAD_PATH=".:...:../srfi" \ guile -c '(display %load-path) (newline)' (. /usr/local/share/guile/3.0 \ /usr/local/share/guile/site/3.0 \ /usr/local/share/guile/site \ /usr/local/share/guile \ ../srfi) (Note: The line breaks, above, are for documentation purposes only, and not required in the actual example.) GUILE_WARN_DEPRECATED As Guile evolves, some features will be eliminated or replaced by newer features. To help users migrate their code as this evolution occurs, Guile will issue warning messages about code that uses features that have been marked for eventual elimination. GUILE_WARN_DEPRECATED can be set to “no” to tell Guile not to display these warning messages, or set to “detailed” to tell Guile to display more lengthy messages describing the warning. See Deprecation. HOME Guile uses the environment variable HOME , the name of your home directory, to locate various files, such as .guile or .guile_history . GUILE_JIT_THRESHOLD Guile has a just-in-time (JIT) code generator that makes running Guile code fast. See Just-In-Time Native Code, for more. The unit of code generation is the function. Each function has its own counter that gets incremented when the function is called and at each loop iteration in the function. When the counter exceeds the GUILE_JIT_THRESHOLD , the function will get JIT-compiled. Set GUILE_JIT_THRESHOLD to -1 to disable JIT compilation, or 0 to eagerly JIT-compile each function as it’s first seen. GUILE_JIT_LOG Set to 1 , 2 , or 3 to give increasing amounts of logging for JIT compilation events. Used for debugging. GUILE_JIT_STOP_AFTER Though we have tested the JIT compiler as well as we can, it’s possible that it has bugs. If you suspect that Guile’s JIT compiler is causing your program to fail, set GUILE_JIT_STOP_AFTER to a positive integer indicating the maximum number of functions to JIT-compile. By bisecting over the value of GUILE_JIT_STOP_AFTER , you can pinpoint the precise function that is being miscompiled.

4.3 Guile Scripting

Like AWK, Perl, or any shell, Guile can interpret script files. A Guile script is simply a file of Scheme code with some extra information at the beginning which tells the operating system how to invoke Guile, and then tells Guile how to handle the Scheme code.

4.3.1 The Top of a Script File

The first line of a Guile script must tell the operating system to use Guile to evaluate the script, and then tell Guile how to go about doing that. Here is the simplest case:

The first two characters of the file must be ‘ #! ’. The operating system interprets this to mean that the rest of the line is the name of an executable that can interpret the script. Guile, however, interprets these characters as the beginning of a multi-line comment, terminated by the characters ‘ !# ’ on a line by themselves. (This is an extension to the syntax described in R5RS, added to support shell scripts.)

’. Immediately after those two characters must come the full pathname to the Guile interpreter. On most systems, this would be ‘ /usr/local/bin/guile ’.

’. Then must come a space, followed by a command-line argument to pass to Guile; this should be ‘ -s ’. This switch tells Guile to run a script, instead of soliciting the user for input from the terminal. There are more elaborate things one can do here; see The Meta Switch.

’. This switch tells Guile to run a script, instead of soliciting the user for input from the terminal. There are more elaborate things one can do here; see The Meta Switch. Follow this with a newline.

The second line of the script should contain only the characters ‘ !# ’ — just like the top of the file, but reversed. The operating system never reads this far, but Guile treats this as the end of the comment begun on the first line by the ‘ #! ’ characters.

’ — just like the top of the file, but reversed. The operating system never reads this far, but Guile treats this as the end of the comment begun on the first line by the ‘ ’ characters. If this source code file is not ASCII or ISO-8859-1 encoded, a coding declaration such as coding: utf-8 should appear in a comment somewhere in the first five lines of the file: see Character Encoding of Source Files.

should appear in a comment somewhere in the first five lines of the file: see Character Encoding of Source Files. The rest of the file should be a Scheme program.

Guile reads the program, evaluating expressions in the order that they appear. Upon reaching the end of the file, Guile exits.

4.3.2 The Meta Switch

Guile’s command-line switches allow the programmer to describe reasonably complicated actions in scripts. Unfortunately, the POSIX script invocation mechanism only allows one argument to appear on the ‘ #! ’ line after the path to the Guile executable, and imposes arbitrary limits on that argument’s length. Suppose you wrote a script starting like this:

#!/usr/local/bin/guile -e main -s !# (define (main args) (map (lambda (arg) (display arg) (display " ")) (cdr args)) (newline))

The intended meaning is clear: load the file, and then call main on the command-line arguments. However, the system will treat everything after the Guile path as a single argument — the string "-e main -s" — which is not what we want.

As a workaround, the meta switch \ allows the Guile programmer to specify an arbitrary number of options without patching the kernel. If the first argument to Guile is \ , Guile will open the script file whose name follows the \ , parse arguments starting from the file’s second line (according to rules described below), and substitute them for the \ switch.

Working in concert with the meta switch, Guile treats the characters ‘ #! ’ as the beginning of a comment which extends through the next line containing only the characters ‘ !# ’. This sort of comment may appear anywhere in a Guile program, but it is most useful at the top of a file, meshing magically with the POSIX script invocation mechanism.

Thus, consider a script named /u/jimb/ekko which starts like this:

#!/usr/local/bin/guile \ -e main -s !# (define (main args) (map (lambda (arg) (display arg) (display " ")) (cdr args)) (newline))

Suppose a user invokes this script as follows:

$ /u/jimb/ekko a b c

Here’s what happens:

the operating system recognizes the ‘ #! ’ token at the top of the file, and rewrites the command line to: /usr/local/bin/guile \ /u/jimb/ekko a b c This is the usual behavior, prescribed by POSIX.

’ token at the top of the file, and rewrites the command line to: When Guile sees the first two arguments, \ /u/jimb/ekko , it opens /u/jimb/ekko , parses the three arguments -e , main , and -s from it, and substitutes them for the \ switch. Thus, Guile’s command line now reads: /usr/local/bin/guile -e main -s /u/jimb/ekko a b c

, it opens , parses the three arguments , , and from it, and substitutes them for the switch. Thus, Guile’s command line now reads: Guile then processes these switches: it loads /u/jimb/ekko as a file of Scheme code (treating the first three lines as a comment), and then performs the application (main "/u/jimb/ekko" "a" "b" "c") .

When Guile sees the meta switch \ , it parses command-line argument from the script file according to the following rules:

Each space character terminates an argument. This means that two spaces in a row introduce an argument "" .

. The tab character is not permitted (unless you quote it with the backslash character, as described below), to avoid confusion.

The newline character terminates the sequence of arguments, and will also terminate a final non-empty argument. (However, a newline following a space will not introduce a final empty-string argument; it only terminates the argument list.)

The backslash character is the escape character. It escapes backslash, space, tab, and newline. The ANSI C escape sequences like

and \t are also supported. These produce argument constituents; the two-character combination

doesn’t act like a terminating newline. The escape sequence \ NNN for exactly three octal digits reads as the character whose ASCII code is NNN . As above, characters produced this way are argument constituents. Backslash followed by other characters is not allowed.

4.3.3 Command Line Handling

The ability to accept and handle command line arguments is very important when writing Guile scripts to solve particular problems, such as extracting information from text files or interfacing with existing command line applications. This chapter describes how Guile makes co