Lisp In Small Pieces for Modern Schemes
This repository contains source code from the book Lisp In Small Pieces by Christian Queinnec, updated to work with modern versions of Bigloo, MIT Scheme, and Guile.
Setting up an environment
If you want to run the code in this repo, you have the following options:
- Use Virtualbox with Vagrant
- Use Virtualbox without Vagrant
- Use Docker
- Install dependencies yourself without using the provided virtual machines
If you have a reasonable internet connection and don't mind downloading ~500MB of virtual machine / docker images, then options 1-3 are the easiest, and provide the only tested and known-working environments. The virtual machines are Arch Linux x86_64 systems with all required dependencies pre-installed.
Using Virtualbox with Vagrant
Using Vagrant is an easy way to get up and running with an environment suitable for running the code in this repo. Assuming you already have vagrant and virtualbox installed, just do the following:
mkdir lisp-in-small-pieces
cd lisp-in-small-pieces
vagrant init appleby/lisp-in-small-pieces-vm
vagrant up # Wait for vagrant to download the box and run it.
vagrant ssh
You should be logged in to the virtual machine as the vagrant
user.
You can now skip to the section Running the Code.
Using Virtualbox without Vagrant
If you want to use a known-working Virtualbox VM but don't want to install Vagrant, you can download a tarball that contains an ovf and the associated virtual disk here.
Download the virtualbox tarball, extract it, and import the resulting
ovf into Virtualbox. You can login to the VM either via the console or
ssh with user vagrant
and password vagrant
.
You can now skip to the section Running the Code.
Using Docker
docker pull appleby/lisp-in-small-pieces
docker run -it --rm appleby/lisp-in-small-pieces
Docker should start the container and drop you into a bash shell.
You can now skip to the section Running the Code.
Installing Dependencies Yourself
This method is not recommended, but is provided for curmudgeons like myself who resent being told to download a 500MB virtual machine just to run some scheme code. Of course if you go this route, figuring out why everything is broken and fixing it will likely take 10x as long as downloading the virtual machine image in the first place, but at least you'll sleep secure knowing you didn't take the easy way out.
Here are the dependencies required to run the grand.test
target,
including the version numbers that are installed in the above
mentioned virtual machines. The exact version numbers are not a hard
requirement, nor a guarantee of a working build. They are included
only for reference.
- GCC 10.2.0
- GNU Make 4.3
- GNU Binutils 2.35 (ar, ranlib, size, ...)
- GNU coreutils 8.32 (uname, time, chmod, tee, nice, ...)
- GNU bash 5.0.018 (invoked as
sh
, so any Bourne shell likely OK) - GNU grep 3.4
- Perl 5.32.0
- One or more of the following schemes
- bigloo 4.3h
- guile 2.2.6
- mit-scheme 10.1.11
In addition to the above required dependencies, the following optional
dependencies are needed by certain tests which are not included in the
grand.test
target, but which may be run individually.
- GNU indent 2.2.12
- Caml Light 0.8.2
Once you have the dependencies installed, you can keep your fingers crossed and skip to Running the Code.
Running the Code
-
Clone this repo.
git clone https://github.com/appleby/lisp-in-small-pieces.git && cd lisp-in-small-pieces
-
Edit the
Makefile
and set theMYSCHEME
variable to the scheme interpreter you want. The supported values forMYSCHEME
are:bigloo
,guile
, andmit
. -
Run
make grand.test
ormake grand.test.quietly
to run the test suite. Running the tests will take a while, but at the end you should see a message that says "All tests passed."
If you want to temporarily try running the tests with a different
scheme interpreter, you can set the MYSCHEME
variable when invoking
make, like so: make MYSCHEME=guile grand.test.quietly
. Of course,
you can replace guile
in the previous examples with any valid value
for MYSCHEME
.
If you don't want to run the full test suite, but only the tests for a
particular chapter of the book, you can specify the targets you want
individually. For example, make test.chap5f
. See the Makefile for a
list of available targets.
If you want to run all tests for all schemes, run make all.test
. You
probably don't want to run this target though, as it takes quite a
while to complete. The all.test
target is mostly useful for testing
changes to this repo.
What happened to Gambit support?
Previous versions of this repo included support for Gambit scheme by
setting MYSCHEME=gsi
. Gambit support was dropped in v0.6 due to a
bug in Gambit's
define-syntax at the
time of release (Gambit v4.9.3).
If you really want Gambit support, you can checkout the v0.5 tag of this repo and make sure you download the corresponding v0.5 release of whatever virtual image you want (vagrant, virtualbox ovf, docker).
What happened to the VMware images?
The VMware images were produced by a HashiCorp Atlas build. Atlas is no longer free, so I don't produce the VMware builds anymore. If you want, you can run the v0.3 VMware vagrant box or ovf and use it with the v0.3 tag in this repo. For example, to use the vmware vagrant box, assuming you have a vmware vagrant license, etc.
mkdir lisp-in-small-pieces
cd lisp-in-small-pieces
vagrant init --box-version 0.3 appleby/lisp-in-small-pieces-vm
vagrant up --provider vmware
vagrant ssh
Once you're logged in to the vm:
git clone https://github.com/appleby/lisp-in-small-pieces.git
cd lisp-in-small-pieces
git checkout v0.3
Failing test.reflisp
The test.reflisp
target is a test of the reflective interpreter from
chapter 8 of the book, and comes with the following disclaimer/warning
at the top of src/chap8k.scm:
;;; Adaptation of the reflective interpreter to Scheme->C, Bigloo or
;;; SCM. This is very messy, very hacky and poses a lot of problems
;;; with hygienic macros so expansion is done by hand.
Most of the hacks are related to the fact that the reflective
interpreter redefines (and allows modification of) special forms like
quote
, if
, set!
, and lambda
.
I'm not planning to fix the test.reflisp
target since:
- I suspect it'll take more time than I want to spend to get it working (and it may not even be possible for all Schemes).
- There is already a working test of the reflective interpreter in
test.chap8j
. Thetest.chap8j
target runs exactly the same reflisp code, but runs it in the byte-code interpreter of chapter 7 rather than on the native scheme.
Other Schemes
In addition to bigloo and mit-scheme the original sources also supported elk, scheme2c, and scm. I'm not planning to get those working myself, but pull requests are welcome.
Guile was not supported in the original sources.
Gambit was previously supported, but has been dropped for now do to a bug in define-syntax (see above).
More Info
For a lot more info, see the original README file.