ikarus/doc/ikarus-scheme-users-guide.tex

2444 lines
82 KiB
TeX
Raw Normal View History

%!TEX TS-program = xelatex
\documentclass[onecolumn, 12pt, twoside, openright, dvipdfm]{book}
\usepackage{fontspec}
\usepackage{hanging}
\usepackage{xltxtra}
\defaultfontfeatures{Scale=MatchLowercase}
2007-10-22 16:47:51 -04:00
%\setmainfont[Mapping=tex-text]{Cochin}
%\setmainfont[Mapping=tex-text]{Palatino}
2007-10-22 16:47:51 -04:00
%\setmainfont[Mapping=tex-text]{Baskerville}
%\setmainfont[Mapping=tex-text]{Perpetua}
%\setmainfont[Mapping=tex-text]{Lido STF}
%\setmainfont[Mapping=tex-text]{Perpetua}
\setmainfont[Mapping=tex-text]{Charis SIL}
%\setmainfont[Mapping=tex-text]{Gentium}
%\setmainfont[Mapping=tex-text]{DejaVu Serif}
%\setmainfont[Mapping=tex-text]{Palatino}
%\setmainfont[Mapping=tex-text]{URWPalladioL}
%\setmainfont[Mapping=tex-text]{GentiumAlt}
\setsansfont[Mapping=tex-text]{Geneva}
%\setmonofont{DejaVu Sans Mono}
%\setmonofont{Monaco}
\setmonofont[Scale=0.95]{Inconsolata}
\usepackage{fancyhdr}
\usepackage{makeidx}
2007-10-22 16:47:51 -04:00
\usepackage{fancyvrb}
\makeindex
\usepackage[dvipdfm,CJKbookmarks,bookmarks=true,bookmarksopen=true]{hyperref}
\hypersetup{
pdftitle={Ikarus Scheme User's Guide},
pdfauthor={Abdulaziz Ghuloum},
pdfkeywords={Scheme, R6RS, Compiler, Ikarus},
bookmarksnumbered=true,
pagebackref=true,
breaklinks=true,
% pdfview=FitH, % Or try pdfstartview={FitV}, This lead to uncorrect bookmarks
urlcolor=blue,
colorlinks=true,
citecolor=blue, %citeref's color
linkcolor=blue,
}
\usepackage{rotating}
\usepackage{multicol,ragged2e}
\renewcommand{\sectionmark}[1]{\markright{\thesection\ #1}}
\fancyhf{}
\fancyhead[LE,RO]{\bfseries\thepage}
\fancyhead[LO]{\bfseries\rightmark}
\fancyhead[RE]{\bfseries\leftmark}
\renewcommand{\headrulewidth}{0pt}
\renewcommand{\footrulewidth}{0pt}
\renewcommand{\headheight}{15pt}
\newcommand{\coderefpage}[1]{figure~\ref{#1}, p.~\pageref{#1}}
\newcommand{\figrefpage}[1]{figure~\ref{#1}, p.~\pageref{#1}}
\newcommand{\deflabelref}[2]{\texttt{#1}~(page~\pageref{#2})}
\newcommand{\defref}[1]{\deflabelref{#1}{#1}}
\newcommand{\coderef}[1]{figure~\ref{#1}}
\newcommand{\figref}[1]{figure~\ref{#1}}
\newcommand{\secref}[1]{section~\ref{#1}}
\newcommand{\rnrs}[1]{R$^{\mathrm{#1}}$RS}
\newcommand{\BoxedText}[2]{
\vspace{.05in}
\begin{center}
\begin{tabular}{|p{4.6in}|} {\large \emph{#1}} #2 \end{tabular}
\end{center}
\vspace{.05in}
}
\newcommand{\testfile}[2]{\texttt{tests-{\ref{#1}}-{#2}.ss}}
2007-10-22 16:47:51 -04:00
\newcommand{\idxtt}[1]{\index{#1 @ \texttt{#1}}\texttt{#1}}
\newenvironment{Language}
{
\begin{center}
\begin{tabular}{|p{4.5in}|} {\large \emph{Input Language:}}
\begin{center}
\begin{tabular}{@{}r@{ }c@{ }l@{}}
}{
\end{tabular}
\end{center}
\end{tabular}
\end{center}
}
2007-10-22 16:47:51 -04:00
\DefineVerbatimEnvironment{CodeInline}{Verbatim}
{gobble=0, xleftmargin=2em, xrightmargin=0em,
%numbers=left, numbersep=2mm,
frame=lines ,framerule=1pt}
\DefineVerbatimEnvironment{CodeInlineIdx}{Verbatim}
{gobble=0, xleftmargin=3em, xrightmargin=0em,
numbers=left, numbersep=1ex,
frame=lines ,framerule=1pt}
2007-11-19 23:19:42 -05:00
\newcommand{\idxlabeldefun}[5]{
\vspace{1ex}
\rule{\textwidth}{2pt}
{\phantomsection\index{#1@\texttt{#2}}\label{#3}{\Large\texttt{#4}}\hfill\textbf{#5}}\\}
2007-11-19 23:19:42 -05:00
\newcommand{\idxdefun}[3]{\idxlabeldefun{#1}{#2}{#1}{#2}{#3}}
\newcommand{\defun}[2]{\idxdefun{#1}{#1}{#2}}
\begin{document}
\frontmatter
\VerbatimFootnotes
\title{Ikarus Scheme User's Guide}
\author{Abdulaziz Ghuloum}
\pagestyle{empty}
\mbox{}
\vspace{3in}
\newcommand{\fstpagefont}[0]
{\fontspec{Charis SIL}}
{ \fontsize{66}{66} \fstpagefont{}
\noindent Ikarus Scheme\\ User's Guide\\ }
\noindent \rule{\textwidth}{6pt}
{\fontsize{18}{18} \fstpagefont{}
2008-01-31 22:21:44 -05:00
\hfill{} (Preliminary Document) \hfill Version~0.0.3 }
\vfill
{ \fontsize{24}{24} \fstpagefont{}
\hfill{} Abdulaziz Ghuloum}
{ \fontsize{18}{18} \fstpagefont{}
\hfill{} \today \\}
\newpage
\mbox{}
\vfill{}
%\addcontentsline{toc}{section}{Copyrights}
\noindent
Ikarus Scheme User's Guide\\
Copyright \copyright{} 2007,2008, Abdulaziz Ghuloum\\
{\small
\noindent
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3 as
published by the Free Software Foundation.
\\ \\
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
\\ \\
You should have received a copy of the GNU General Public License
along with this program. If not, see
\url{http://www.gnu.org/licenses/}.
}
% Permission is granted to copy, distribute and/or modify this
% document under the terms of the GNU Free Documentation License,
% Version 1.2 published by the Free Software
% Foundation; with no Invariant Sections, the Front-Cover Texts
% being \emph{``Ikarus Scheme User's Guide''}, and
% no Back-Cover Texts. A copy of the license is included in the
% section entitled ``GNU Free Documentation License''.
\newpage
\pagestyle{fancy}
\phantomsection
\addcontentsline{toc}{section}{Contents}
\tableofcontents
\newpage
\mainmatter
\setlength{\parindent}{0pt}
\setlength{\parskip}{2.0ex plus 0ex minus 0ex}
\chapter{Getting Started}
\section{Introduction}
Ikarus Scheme is an implementation of the Scheme programming
language. The preliminary release of Ikarus implements the majority
of the features found in the current standard, the
Revised$^\mathrm{6}$ report on the algorithmic language
Scheme\cite{r6rs} including full \rnrs{6} library and script syntax,
syntax-case, unicode strings, bytevectors, user-defined record
types, exception handling, conditions, and enumerations. More than
94\% of the \rnrs{6} procedures and keywords are currently
implemented and subsequent releases will proceed towards brining
Ikarus to full \rnrs{6} conformance.
The main purpose behind releasing Ikarus early is to give Scheme
programmers the opportunity to experiment with the various new
features that were newly introduced in \rnrs{6}. The most important
of such features is the ability to structure large programs into
libraries; where each library extends the language through
procedural and syntactic abstractions. Many useful libraries can be
written using the currently supported set of \rnrs{6} features
including text processing tools, symbolic logic systems,
interpreters and compilers, and many mathematical and scientific
packages. It is my hope that this release will encourage the
Scheme community to write and to share their most useful \rnrs{6}
libraries.
2007-10-22 16:47:51 -04:00
\newpage
\section{Technology overview}
Ikarus Scheme provides the programmer with many advantages:
\textbf{Optimizing code generator:} The compiler's backend employs
state of the art technologies in code generation that produce fast
efficient machine code. When developing computationally intensive
programs, one is not constrained by using a slow interpreter.
\textbf{Fast incremental compilation:} Every library and script is
quickly compiled to native machine code. When developing large
software, one is not constrained by how slow the batch compiler
runs.
\textbf{Robust and fine-tuned standard libraries:} The standard
libraries are written such that they perform as much error checking
as required to provide a safe and fast runtime environment.
\textbf{Multi-generational garbage collector:} The
BiBOP\cite{dybvig:sm} based garbage collector used in Ikarus allows
the runtime system to expand its memory footprint as needed. The
entire 32-bit virtual address space could be used and unneeded
memory is released back to the operating system.
\textbf{Supports many operating systems:} Ikarus runs on the most
popular and widely used operating systems for servers and personal
computers. The supported systems include Mac~OS~X,
GNU/Linux, FreeBSD, NetBSD, and Microsoft Windows.
\section{System requirements}
\subsection{Hardware}
Ikarus Scheme runs on the IA-32 (\emph{x86}) architecture
supporting SSE2 extensions. This includes the Athlon 64,
Sempron 64, and Turion 64 processors from AMD and the Pentium 4, Xeon,
Celeron, Pentium M, Core, and Core2 processors from Intel. The
system does not run on Intel Pentium III or earlier
processors.
The Ikarus compiler generates SSE2 instructions to handle Scheme's
IEEE floating point representation (\emph{flonums}) for inexact
numbers.
\subsection{Operating systems}
Ikarus is tested under the following operating systems:
\begin{itemize}
\item Mac OS X version 10.4 and 10.5.
\item Linux 2.6.18 (Debian, Fedora, Gentoo, and Ubuntu).
\item FreeBSD version 6.2.
\item NetBSD version 3.1.
\item Microsoft Windows XP (using Cygwin 1.5.24).
\end{itemize}
\subsection{Additional software}
\begin{itemize}
\item\textbf{GMP:} Ikarus uses the GNU Multiple Precision Arithmetic
Library (GMP) for some bignum arithmetic operations. To build
Ikarus from scratch, GMP version 4.2 or better must be installed
along with the required header files. Pre-built GMP packages are
available for most operating systems. Alternatively, GMP can be
downloaded from \\
\url{http://gmplib.org/}.
\BoxedText{Note:}{Ikarus runs in 32-bit mode only.
To run it in 64-bit environments, you will have to obtain the 32-bit
version of GMP, or compile it yourself after adding \texttt{ABI=32}
to its configuration options.}
\item\textbf{GCC:} The GNU C Compiler is required to build the Ikarus
executable (e.g. the garbage collector, loader, and OS-related
runtime). GCC versions 4.1 and 4.2 were successfully used to build
Ikarus.
2007-11-19 23:19:42 -05:00
\item\textbf{Autoconf and Automake:} The GNU Autoconf (version 2.61)
and GNU Automake (version 1.10) tools are required if one
wishes to modify the Ikarus source base. They are not
required to build the official release of Ikarus.
\item\textbf{\XeLaTeX{}:} The \XeLaTeX\ typesetting system is
required for building the documentation. \XeLaTeX\ (and \XeTeX) is
an implementation of the \LaTeX\ (and \TeX) typesetting system.
\XeLaTeX\ can be obtained from \url{http://scripts.sil.org/xetex}
and is included with \TeX-Live\footnote{
\url{http://tug.org/texlive/}} and and
Mac-\TeX\footnote{\url{http://tug.org/mactex/}} distributions.
\end{itemize}
\section{Installation}
If you are familiar with installing Unix software on your system,
then all you need to know is that Ikarus uses the standard
installation method found in most other Unix software. Simply run
the following commands from the shell:
\begin{verbatim}
$ tar -zxf ikarus-n.n.n.tar.gz
$ cd ikarus-n.n.n
$ ./configure [--prefix=path] [CFLAGS=-I/dir] [LDFLAGS=-L/dir]
$ make
$ make install
$
\end{verbatim}
The rest of this section describes the build process in more
details. It is targeted to users who are unfamiliar with steps
mentioned above.
\subsection{Installation details}
\begin{enumerate}
\item Download the Ikarus source distribution. The source is
distributed as a \texttt{gzip}-compressed \texttt{tar} file
(\texttt{ikarus-n.n.n.tar.gz} where \texttt{n.n.n} is a 3-digit
number indicating the current revision). The latest revision can be
downloaded from the following URL:\\
\url{http://www.cs.indiana.edu/~aghuloum/ikarus/}
\item Unpack the source distribution package. From your shell
command, type:
\begin{verbatim}
$ tar -zxf ikarus-n.n.n.tar.gz
$
\end{verbatim}
This creates the base directory \texttt{ikarus-n.n.n}.
\item Configure the build system by running the \texttt{configure}
script located in the base directory. To do this, type the
following commands:
\begin{verbatim}
$ cd ikarus-n.n.n
$ ./configure
checking build system type... i386-apple-darwin8.10.1
checking host system type... i386-apple-darwin8.10.1
...
configure: creating ./config.status
config.status: creating Makefile
config.status: creating src/Makefile
config.status: creating scheme/Makefile
config.status: creating doc/Makefile
config.status: executing depfiles commands
$
\end{verbatim}
This configures the system to be built then installed in the
system-wide location (binaries are installed in
\texttt{/usr/local/bin}) . If you wish to install it
in another location (e.g. in your home directory), you can supply
a \texttt{--prefix} location to the \texttt{configure} script as
follows:
\begin{verbatim}
$ ./configure --prefix=/path/to/installation/location
\end{verbatim}
The \texttt{configure} script will fail if it cannot locate the
location where GMP is installed. If running \texttt{configure}
fails to locate GMP, you should supply the location in which the GMP
header file, \texttt{gmp.h}, and the GMP library file,
\texttt{libgmp.so}, are installed. This is done by supplying the
two paths in the \texttt{CFLAGS} and \texttt{LDFLAGS} arguments:
\begin{verbatim}
$ ./configure CFLAGS=-I/path/to/include LDFLAGS=-L/path/to/lib
\end{verbatim}
\item Build the system by running:
\begin{verbatim}
$ make
\end{verbatim}
This performs two
tasks. First, it builds the \texttt{ikarus} executable from the C
files located in the \texttt{src} directory. It then uses the
\texttt{ikarus} executable and the pre-built
\texttt{ikarus.boot.orig} boot file to rebuild the Scheme boot image
file \texttt{ikarus.boot} from the Scheme sources located in the
\texttt{scheme} directory.
\item Install Ikarus by typing:
\begin{verbatim}
$ make install
\end{verbatim}
If you are installing Ikarus in a system-wide location, you might
need to have administrator privileges (use the \texttt{sudo} or
\texttt{su} commands).
\item Test that Ikarus runs from the command line.
\begin{verbatim}
$ ikarus
Ikarus Scheme version 0.0.3
Copyright (c) 2006-2008 Abdulaziz Ghuloum
>
\end{verbatim}
If you get the prompt, then Ikarus was successfully installed on
your system. You may need to update the \texttt{PATH} variable in
your environment to contain the directory in which the
\texttt{ikarus} executable was installed.
Do not delete the \texttt{ikarus-n.n.n} directory from which you
configured, built, and installed Ikarus. It will be needed if you
decide at a later time to uninstall Ikarus.
\end{enumerate}
\subsection{Uninstalling Ikarus}
To uninstall Ikarus, use the following steps:
\begin{verbatim}
$ cd path/to/ikarus-n.n.n
$ make uninstall
$
\end{verbatim}
\section{\index{Command-line switches}Command-line switches}
The \texttt{ikarus} executable recognizes a few command-line
switches that influence how Ikarus starts.
\begin{itemize}
\item \texttt{ikarus -h}
The presence of the \texttt{-h} flag causes \texttt{ikarus} to
display a help message then exits. The help message summarizes the
command-line switches. No further action is performed.
\item \texttt{ikarus -b path/to/boot/file.boot}
The \texttt{-b} flag (which requires an extra argument) directs
\texttt{ikarus} to use the specified boot file as the initial system
boot file. \index{Boot files} The boot file is a binary file that
contains all the code and data of the Scheme system. In the absence
2007-11-19 23:19:42 -05:00
of \texttt{-b} flag, the executable will use the default boot file.
Running \texttt{ikarus~-h} shows the location where the default boot
file was installed.
The rest of the command-line arguments are recognized by the
standard Scheme run time system. They are processed after the
boot file is loaded.
\item \texttt{ikarus --r6rs-script script-file-name [arguments ...]}
2007-10-22 16:47:51 -04:00
\index{R6RS Script@\rnrs{6} Script} The \texttt{--r6rs-script} argument
instructs Ikarus that the supplied file is an \rnrs{6} script. See
Section~\ref{sec:scripts} for a short introduction to writing \rnrs{6}
scripts. The script file name and any additional optional
\texttt{arguments}
can be obtained by calling the
2007-10-22 16:47:51 -04:00
\idxtt{command-line} procedure.
\begin{verbatim}
$ cat test.ss
(import (rnrs))
(write (command-line))
(newline)
$ ikarus --r6rs-script test.ss hi there
("test.ss" "hi" "there")
$
\end{verbatim}
\item \texttt{ikarus files ... [-- arguments ...]}
The lack of an \texttt{--r6rs-script} argument causes Ikarus to
start in interactive mode. Each of the \texttt{files} is first
loaded, in the interaction environment. The interaction environment
initially contains all the bindings exported from the
\texttt{(ikarus)} library (see Chapter~\ref{chapter:ikarus}). The
optional \texttt{arguments} following the \texttt{--} marker can be
obtained by calling the \texttt{command-line} procedure. In
interactive mode, the first element of the returned list will be the
string \texttt{"*interactive*"}, corresponding to the script name in
\rnrs{6}-script mode.
\BoxedText{Note:}{The interactive mode is intended for quickly
experimenting with the built-in features. It is intended neither
for developing applications nor for writing any substantial pieces
of code. The main reason for this is that the interaction between
\rnrs{6} libraries and the interactive environment is not well
understood. We hope to achieve better interaction between the two
subsystems in the future.}
\end{itemize}
\section{Using \texttt{scheme-script}}
2007-11-19 23:19:42 -05:00
Scheme scripts can be executed using the
\texttt{ikarus~--r6rs-script~\textit{script-name}} command as
described in the previous section. For convenience, Ikarus
follows the \rnrs{6} recommendations and installs a wrapper program
called \texttt{scheme-script}. Typically, a script you write would
start with a \texttt{\#!}\ line that directs your operating system
to the interpreter used to evaluate the script file. The following
example shows a very simple script that uses the
\texttt{scheme-script} command.
\begin{CodeInline}
#!/usr/bin/env scheme-script
(import (rnrs))
(display "Hello World\n")
\end{CodeInline}
If the above script was placed in a file called
\texttt{hello-world}, then one can make it executable using the
\texttt{chmod} Unix command.
2007-11-19 23:19:42 -05:00
\begin{verbatim}
$ cat hello-world
#!/usr/bin/env scheme-script
(import (rnrs))
(display "Hello World\n")
$ chmod 755 hello-world
$ ./hello-world
Hello World
$
\end{verbatim}
\BoxedText{Under Mac OS X,}{if a script name ends with the
\texttt{.command} extension, then it can be executed from the Finder
by double-clicking on it. This brings up a terminal window in which
the script is executed. The \texttt{.command} extension can be
hidden from the \emph{Get Info} item from the Finder's File menu.}
2007-11-19 23:19:42 -05:00
\newpage
\section{Mapping library names to file names}
2007-11-19 23:19:42 -05:00
The name of an \rnrs{6} library consists of a non-empty list of
identifiers (symbols), followed by an optional version number. All
of the standard \rnrs{6} libraries are built into Ikarus, thus
importing any one of them does not require any special action other
than listing the library name in the \texttt{import} part of a
library or a script. The same holds for the \texttt{(ikarus)}
library (chapter~\ref{chapter:ikarus},
page~\pageref{chapter:ikarus}).
When writing a new library to a file, Ikarus uses a simple mechanism
to map library names to file names. A library name is converted to
a file path by joining the library identifiers with a path
separator, e.g. \verb|"/"|.
\begin{center}
\begin{tabular}{lcl}
Library Name & \hspace{2em}$\Rightarrow$\hspace{2em} & File name \\
\hline
\verb|(foo)| & $\Rightarrow$ & \verb|foo| \\
\verb|(foo bar)| & $\Rightarrow$ & \verb|foo/bar| \\
\verb|(foo bar baz)| & $\Rightarrow$ & \verb|foo/bar/baz|
\end{tabular}
\end{center}
Having mapped a library name to a file path, Ikarus attempts to
locate that file in one of several locations. The locations
attempted depend on two settings: the search path and the file
prefix set (e.g., \verb|.sls|, \verb|.ss|, \verb|.scm|, etc.).
First, Ikarus attempts to locate the file in the current working
directory from which Ikarus was invoked. In the current working
directory, Ikarus enumerates all file prefixes first before
searching other locations. If the file is not found in the current
directory, Ikarus tries to find it in the Ikarus library directory.
The Ikarus library directory is determined when Ikarus is installed
(based on the \texttt{--prefix} argument that was passed to the
\texttt{configure} script). If Ikarus failes to locate the library
file, it raises an exception and exits. See
Chapter~\ref{chapter:contributed} for more details about the library
locations.
\BoxedText{Tip:}{Use simple library names for the libraries that
you define. Library names that contain non-printable characters,
complex punctuations, or unicode may pose a challenge for some
operating systems. If Ikarus cannot find a library, it will raise
an error listing the locations in which it looked, helping you move
the library file to a place where Ikarus can find it.}
\section{Writing cross-implementation libraries}
When searching for a library, Ikarus appends a prefix (e.g.,
\verb|.ss|) to the appropriate file name (e.g., \verb|foo/bar|).
The initial set of file extensions are: \verb|.ikarus.sls|,
\verb|.ikarus.ss|, \verb|.ikarus.scm|,
\verb|.sls|, \verb|.ss|, and \verb|.scm|.
The list of file extensions are searched sequentially. As a
consequence, files ending with the \verb|.ikarus.*| prefixes are
given precedence over files that have generic Scheme extensions.
The rationale for this behavior is to facilitate writing
cross-implementation libraries: ones that take advantage of
implementation-specific features, while at the same time
provide a fail-safe alternative for other \rnrs{6}
implementations.
Consider for example a program which would like to use the
\verb|pretty-print| procedure to format some code, and suppose
furthr that pretty printing is just a nice add-on (e.g., using
\verb|write| suffices, but pretty-printing is \emph{just prettier})
Ikarus exports a good pretty-printing facility in its
\verb|(ikarus)| library. However, since \verb|pretty-print| is not
a standard procedure, a program that uses it would be rendered
unportable to other \rnrs{6} Scheme implementations.
The programmer can put the \verb|.ikarus.*| extensions to use in
this situation. First, the programmer writes two versions of a
\verb|(pretty-printing)| library: one for use by Ikarus, and one
portable for other implementations.
\begin{CodeInline}
(library (pretty-printing) ;;; this is pretty-printing.ikarus.ss
(export pretty-print) ;;; can only be used by Ikarus
(import (only (ikarus) pretty-print)))
\end{CodeInline}
\begin{CodeInline}
(library (pretty-printing) ;;; this is pretty-printing.sls
(export pretty-print) ;;; *portable* though not very pretty.
(import (rnrs)) ;;; for any other implementation
(define (pretty-print x port)
(write x port)
(newline port)))
\end{CodeInline}
2007-10-22 16:47:51 -04:00
\chapter{\rnrs{6} Crash Course}
The major difference between \rnrs{5} and \rnrs{6} is the way
in which programs are loaded and evaluated.
In \rnrs{5}, Scheme implementations typically start as an
interactive session (often referred to as the REPL, or
read-eval-print-loop). Inside the interactive session, the user
enters definitions and expressions one at a time using the keyboard.
Files, which also contain definitions and expressions, can be loaded
and reloaded by calling the \texttt{load} procedure. The
environment in which the interactive session starts often contains
implementation-specific bindings that are not found \rnrs{5} and
users may redefine any of the initial bindings. The semantics of
2007-10-22 16:47:51 -04:00
loading a file depends on the state of the environment at the time
the file contents are evaluated.
2007-11-19 23:19:42 -05:00
\index{R6RS Script@\rnrs{6} Script!Import}
%
2007-10-22 16:47:51 -04:00
\rnrs{6} differs from \rnrs{5} in that it specifies how \emph{whole
programs}, or scripts, are compiled and evaluated. An \rnrs{6}
script is closed in the sense that all the identifiers found in the
body of the script must either be defined in the script or imported
from a library. \rnrs{6} also specifies how \emph{libraries} can be
2007-11-19 23:19:42 -05:00
defined and used. While files in \rnrs{5} are typically
\emph{loaded} imperatively into the top-level environments, \rnrs{6}
libraries are \emph{imported} declaratively in scripts and in other
\rnrs{6} libraries.
2007-10-22 16:47:51 -04:00
\section{\label{sec:scripts}Writing a simple script}
An \rnrs{6} script is a set of definitions and expressions preceded
2007-10-22 16:47:51 -04:00
by an \texttt{import} form. The \texttt{import} form specifies
the language (i.e. the variable and keyword bindings) in which the
library body is written. A very simple example of an \rnrs{6}
script is listed below.
\index{Examples!Hello World}
2007-10-22 16:47:51 -04:00
\begin{CodeInline}
2007-11-19 23:19:42 -05:00
#!/usr/bin/env scheme-script
2007-10-22 16:47:51 -04:00
(import (rnrs))
(display "Hello World!\n")
\end{CodeInline}
The first line imports the \texttt{(rnrs)} library. All the
bindings exported from the \texttt{(rnrs)} library are made
available to be used within the body of the script.
2007-10-22 16:47:51 -04:00
The exports of the \texttt{(rnrs)} library include variables
(e.g. \texttt{cons}, \texttt{car}, \texttt{display}, etc.) and
keywords (e.g. \texttt{define}, \texttt{lambda}, \texttt{quote},
etc.). The second line displays the string \texttt{Hello World!}
followed by a new line character.
In addition to expressions, such as the call to \texttt{display} in
the previous example, a script may define some variables. The
script below defines the variable \texttt{greeting} and calls the
procedure bound to it.
\begin{CodeInline}
2007-11-19 23:19:42 -05:00
#!/usr/bin/env scheme-script
2007-10-22 16:47:51 -04:00
(import (rnrs))
(define greeting
(lambda ()
(display "Hello World!\n")))
2007-10-22 16:47:51 -04:00
(greeting)
\end{CodeInline}
Additional keywords may be defined within a script. In the example
below, we define the \texttt{(do-times n exprs ...)} macro that
evaluates the expressions \texttt{exprs} \texttt{n} times. Running
the script displays \texttt{Hello World} 3 times.
\newpage
2007-10-22 16:47:51 -04:00
\begin{CodeInline}
2007-11-19 23:19:42 -05:00
#!/usr/bin/env scheme-script
2007-10-22 16:47:51 -04:00
(import (rnrs))
2007-10-22 16:47:51 -04:00
(define greeting
(lambda ()
(display "Hello World!\n")))
2007-10-22 16:47:51 -04:00
(define-syntax do-times
(syntax-rules ()
[(_ n exprs ...)
(let f ([i n])
(unless (zero? i)
exprs ...
(f (- i 1))))]))
2007-10-22 16:47:51 -04:00
(do-times 3 (greeting))
\end{CodeInline}
2007-10-22 16:47:51 -04:00
\section{Writing simple libraries}
2007-10-22 16:47:51 -04:00
A script is intended to be a small piece of the program---useful
abstractions belong to libraries. The \texttt{do-times} macro that
was defined in the previous section may be useful in places other
than printing greeting messages. So, we can create a small library,
\texttt{(iterations)} that contains common iteration forms.
2007-10-22 16:47:51 -04:00
An \rnrs{6} library form is made of four essential parts: (1) the
library name, (2) the set of identifiers that the library exports,
(3) the set of libraries that the library imports, and (4) the body
of the library.
2007-10-22 16:47:51 -04:00
The library name can be any non-empty list of identifiers.
\rnrs{6}-defined libraries includes \texttt{(rnrs)},
\texttt{(rnrs~unicode)}, \texttt{(rnrs~bytevectors)}, and so on.
2007-10-22 16:47:51 -04:00
The library exports are a set of identifiers that are made available
to importing libraries. Every exported identifier must be bound: it
may either be defined in the library or imported using the
\texttt{import} form. Library exports include variables, keywords,
record names, and condition names.
2007-10-22 16:47:51 -04:00
Library imports are similar to script imports: they specify the set
of libraries whose exports are made visible within the body of the
library.
2007-10-22 16:47:51 -04:00
\index{Invoke}
The body of a library contains definitions (variable, keyword,
record, condition, etc.) followed by an optional set of expressions.
The expressions are evaluated for side effect when needed.
2007-10-22 16:47:51 -04:00
The \texttt{(iteration)} library may be written as follows:
\begin{CodeInline}
(library (iteration)
(export do-times)
(import (rnrs))
2007-10-22 16:47:51 -04:00
(define-syntax do-times
(syntax-rules ()
[(_ n exprs ...)
(let f ([i n])
(unless (zero? i)
exprs ...
(f (- i 1))))])))
\end{CodeInline}
To use the \texttt{(iteration)} library in our script, we add the
name of the library to the script's \texttt{import} form. This
makes all of \texttt{(iteration)}'s exported identifiers, e.g.
\texttt{do-times}, visible in the body of the script.
\begin{CodeInline}
2007-11-19 23:19:42 -05:00
#!/usr/bin/env scheme-script
2007-10-22 16:47:51 -04:00
(import (rnrs) (iteration))
2007-10-22 16:47:51 -04:00
(define greeting
(lambda ()
(display "Hello World!\n")))
2007-10-22 16:47:51 -04:00
(do-times 3 (greeting))
\end{CodeInline}
\section{\rnrs{6} record types}
2007-10-22 16:47:51 -04:00
\rnrs{6} provides ways for users to define new types, called record
types. A record is a fixed-size data structure with a unique type
(called a record type). A record may have any finite number of
fields that hold arbitrary values. This section briefly describes
what we expect to be the most commonly used features of the record
system. Full details are in the \rnrs{6} Standard Libraries
document\cite{r6rs:lib}.
2007-10-22 16:47:51 -04:00
\subsection{Defining new record types}
To define a new record type, use the \texttt{define-record-type}
form. For example, suppose we want to define a new record type for
describing points, where a point is a data structure that has two
fields to hold the point's $x$ and $y$ coordinates. The following
definition achieves just that:
\begin{CodeInline}
(define-record-type point
(fields x y))
\end{CodeInline}
The above use of \texttt{define-record-type} defines the following
procedures automatically for you:
\begin{itemize}
\item The constructor \texttt{make-point} that takes two arguments,
\texttt{x} and \texttt{y} and returns a new record whose type is
point.
\item The predicate \texttt{point?}\ that takes an arbitrary value
and returns \texttt{\#t} if that value is a point, \texttt{\#f}
otherwise.
\item The accessors \texttt{point-x} and \texttt{point-y} that,
given a record of type point, return the value stored in the
\texttt{x} and \texttt{y} fields.
\end{itemize}
Both the \texttt{x} and \texttt{y} fields of the \texttt{point}
record type are \emph{immutable}, meaning that once a record is
created with specific \texttt{x} and \texttt{y} values, they cannot
be changed later. If you want the fields to be \emph{mutable}, then
you need to specify that explicitly as in the following example.
2007-10-22 16:47:51 -04:00
\newpage
\begin{CodeInline}
(define-record-type point
(fields (mutable x) (mutable y)))
\end{CodeInline}
This definition gives us, in addition to the constructor, predicate,
and accessors, two additional procedures:
\begin{itemize}
\item The mutators \texttt{point-x-set!} and \texttt{point-y-set!} that,
given a record of type point, and a new value, sets the value stored in the
\texttt{x} field or \texttt{y} field to the new value.
\end{itemize}
\BoxedText{Note:}{Records in Ikarus have a printable representation
in order to enable debugging programs that use records. Records are
printed in the \texttt{\#[type-name field-values ...]} notation.
For example, \texttt{(write (make-point 1 2))} produces
\texttt{\#[point 1 2]}.}
\subsection{Extending existing record types}
A record type may be extended by defining new variants of a record
with additional fields. In our running example, suppose we want
to define a \texttt{colored-point} record type that, in addition to
being a \texttt{point}, it has an additional field: a \emph{color}.
A simple way of achieving that is by using the following record
definition:
\begin{CodeInline}
(define-record-type cpoint
(parent point)
(fields color))
\end{CodeInline}
Here, the definition of \texttt{cpoint} gives us:
\begin{itemize}
\item A constructor \texttt{make-cpoint} that takes three arguments
(\texttt{x}, \texttt{y}, and \texttt{color} in that order) and returns a
\texttt{cpoint} record.
\item A predicate \texttt{cpoint?}\ that takes a single argument and
determines whether the argument is a \texttt{cpoint} record.
\item An accessor \texttt{cpoint-color} that returns the value of
the \texttt{color} field of a \texttt{cpoint} object.
\end{itemize}
All procedures that are applicable to records of type
\texttt{point} (\texttt{point?}, \texttt{point-x},
\texttt{point-y}) are also applicable to records of type
\texttt{cpoint} since a \texttt{cpoint} is also a \texttt{point}.
\subsection{Specifying custom constructors}
The record type definitions explained so far use the default
constructor that takes as many arguments as there are fields and
returns a new record type with the values of the fields initialized
to the arguments' values. It is sometimes necessary or convenient
to provide a constructor that performs more than the default
constructor. For example, we can modify the definition of our
\texttt{point} record so that the constructor takes either
no arguments, in which case it would return a point located at the
origin, or two arguments specifying the $x$ and $y$ coordinates. We
use the \texttt{protocol} keyword for specifying such constructor as
in the following example:
\begin{CodeInline}
(define-record-type point
(fields x y)
(protocol
(lambda (new)
(case-lambda
[(x y) (new x y)]