/SchemingEssentialLisp

Notes and worked problems from the 1987 text Essential Lisp.

Primary LanguageSchemeOtherNOASSERTION

Exercises from Essential Lisp, not done in Lisp!

Essential Lisp (Anderson, Corbett, and Reiser) is a Common Lisp based text teaches Lisp by doing. The exercises are small, focused, and are suitable for anyone familiar with general programming concepts.

Essential Lisp, Copyright (c) 1987 Addison-Wesley Publishing Company. This is a 1987 paperback edition noted as “published with corrections” on the title page.

Motivation

I’ve used the text to provide some structure as I learn Scheme. The way I like to learn something new is to use it to do something I already know: simple programs to demonstrate language usage to solve straight forward tasks.

Scheme is a Lisp, or is it?

The differences between Lisp and Scheme show up early but can be handled easily. The single biggest stumbling point in the early going was Lisp’s “nil punning”. Most of the usage is the same but the text often specifies nil for a return value when false (#f) would do.

Here are some of the mechanical or textual replacements to help as you through the text.

  • Predicates in Lisp normally end with “p”, as in “listp”, while in Scheme a “?” is used, as in “list?”
  • In place of (defun func (args) …) use (define (func args) …) or (define func (lambda (args) …)).
  • In place of (setq var value) or (set ‘var value) use (define var value) to create and initialize a variable. The define form can be used again to modify the value but using (set! var value) is proper.
  • Some functions dont’ exist in Scheme or have different names. There are some helpers and synonyms in scheming.scm.
    • Scheme does not have a nil symbol.
    • Scheme does not have a last function.
    • Scheme does not have an atom predicate, atomp in Lisp, atom? in Scheme.
  • The booleans t and f are #t and #f in Scheme.
  • On a default condition under cond, where the text uses (t …) use (else …) for clarity. (#t …) works but else seems more common.

Differences that matter to the text, but not to the world at large

Some of the more difficult things to work around from the text. There’s nothing conceptually difficult, but names and availability invalidate a few sections of the text.

Pretty Printing

In Scheme, pretty-print spelled out and not abbreviated pp. You could define a synonym but the default display of lists and atoms is quite readable. The pretty-print function does not display the source code of a function. The various alternative forms presented in chapter two do not work.

As you should be using and editor to write code, this should not present a problem.

Macros

Scheme is a Lisp descendant and has macros. The syntax is different and they are not really required until chapter 13 of the text. Up to chapter 12 ignore the proposed macro replacements for differing functions in the various Lisps in common use when the text was written. Notes in the chapter specific scheme code files will provide alternative functions.

Debugging

The discussion of specific debugging commands in chapter 4 notes that the commands will differ across implementations. Guile provides a back-trace command that I found offers limited help. Appreviated ,bt in the REPL. The code written for the text comprehensible enough that a dedicated debugger should not be needed for the exercises.

Do actually read, not not just skim, any error messages offered.

Input and Output

The function names and behaviors are all different. You can generally replace one name with another and things will work.

Text Function NameScheme EquivalentNotes
printdisplayDoes not return argument
Does not insert newline
readreadMust enable readline
Can lock up Geiser Emacs
princdisplay
terprinewline

At least in Guile, the read function requires that you enable readline if you want it to accept more than a single self defining atom. On Linux this is best done in an initialization file, by convention $HOME/.guile, containing Scheme expressions:

(use-modules (ice-9 readline)) (activate-readline) (use-modules (ice-9 pretty-print))

Using read in a Geiser REPL session often locks up Emacs. For testing functions that require more than a single atom of input I use the Guile REPL in a terminal session.

Lisp prog/return versus let

Scheme doesn’t have anything like prog and return. This is by design. Use the various forms of let.

Looping without loop

Scheme doesn’t have the loop form. Scheme expects you to use recursion. The best Scheme alternative I found was the while form:

(while (test) body…)

I find the Scheme do form to be frustrating. I think of do in terms of while, but the Scheme do is a do until.

See ch06-probs.scm for examples.

Environment

Lisp and Scheme come in many accents. This work was done using GNU Guile 3.0 on Lubuntu 22 with Emacs 28 and Geiser.

Structure of Files

These files exercises, helpers, and notes all combined. Rather than using org-babel or a more formal literate programming structure, notes and instructions are in the form of Lisp comments using the double semicolon form. Files read from top to bottom and definitions/solutions are often followed by simple tests. With Geiser running, the definitions and tests can be evaluated and any output captured and pasted as verification of the solution.

I’ve made an effort to format the chapter problem files so that they can be loaded by a REPL without error. C-c C-b in Emacs with Geiser running, or (load “ch99-probs.scm”) in a REPL session on a terminal.

Most problem solutions have test cases following the code. These are commented expressions with the output noted. The format is:

;; (sexp to test problem) ==> result of evaluating the sexp

Notes in any of the .scm files sometimes ramble as I describe learnings or changes in approach.

File Naming

Each chapter’s problems and solutions are in files named ch99-probs.scm. Some problems, particularly end of chapter optional problems, are complex enough that I put them in their own files. ch05-tictac.scm is one such file.

In addition to the chapter problem files, there are scheming.scm which holds definitions for things the text uses that aren’t directly in Scheme, and doodling.scm which is just a scratch pad of code snippets as I work through the text.

File property-list-helpers.scm is a thin wrapper over the Guile functions for accessing atom properties plus some support functions for testing. Some of the other schemes use a similar syntax to the Common Lisp presented in the text, but Guile does not. The mapping is pretty much one-to-one and using these wrappers should help anyone trying this effort with say Chez or MIT.

Licensing

There’s nothing original here. Just mid level homework. The text provides an answer key already.

Troy Brumley, February 2023.