The Spritely Institute publishes A Scheme Primer

Hello all! I’m happy to announce that we’ve announced a new document: A Scheme Primer!

This grew out of requests from discussions around the whitepaper for an introduction to Scheme’s concepts, and was originally an appendix, but it grew enough that we decided it should be its own thing! (It’ll be removed from being an appendix when I publish the next release of the whitepaper now that we have the separate primer.)

Your feedback, as always, is welcome. This one’s fairly public already, so feel free to spread it around if you like!


4. Basic types, a few small functions

Contains the following example:

(* (- 8 (/ 30 5)) 21)   ; beginning expression
(* (- 8 6) 21)          ; simplify: (/ 30 5) => 6
(* 2 21)                ; simplify: (- 8 6)  => 2
42                      ; simplify: (* 2 21) => 42

We could take advantage of non-canonical whitespace to align the substitutions…

(* (- 8 (/ 30 5)) 21)   ; beginning expression
(* (- 8 6       ) 21)   ; simplify: (/ 30 5) => 6
(* 2              21)   ; simplify: (- 8 6)  => 2
42                      ; simplify: (* 2 21) => 42

…and maybe make the example more clear to the novice reader.

This example appears again in:

10. Mutation, assignment, and other kinds of side effects


9. Iteration and recursion

Contains the following example:

(define (build-tree depth)
  (if (= depth 0)
      (list depth
            (build-tree (- depth 1))
            (build-tree (- depth 1)))))

The subsequent explanation includes the phrase “more work needs to be done, as cons sits waiting for its results”, which should be “more work needs to be done, as list sits waiting for its results”.

In footnote 16, the phrase “managing change such that the user need think of them;” should be “managing change such that the user need not think of them;”


Apparently it is bad form to make multiple reply-posts, so I’ve consolidated my prior edits into the previous two posts, and will add any remaining edits to this one…

12. Scheme in Scheme

“Supplying only two operators, + and - , we are able to compute the Fibonacci sequence:” should be “Supplying only two operators, + and = , we are able to compute the Fibonacci sequence:”

In the section explaining the implementation of lambda, you say:

the procedure we return recursively calls evaluate against the body expression of the lambda we are matching against, but with a newly extended environment

This is the point where a choice is made between lexical and dynamic scoping. I think it would be worth pointing out that the environment where lambda is evaluated is captured and used in place of the dynamic environment where the procedure is invoked. Perhaps with a corresponding back-reference in the discussion of procedure application, pointing out that the arguments are evaluated in a different environment than the body of the lambda.

1 Like

Thanks for all the good catches! I’m on vacation so allegedly I’m not even reading this let alone replying to it or lord forbid fixing things :wink:

Yes that’s well put. I thought a fun follow-up document to this, some day, might be to show off (borrowing from SICP’s Variations on a Scheme) how with just a couple of small tweaks one can switch to dynamic scope or make it prolog-like or etc. Maybe at some point in the future…

1 Like

Thanks again @dale.schumacher ! I integrated almost all of your suggestions, but I didn’t do the alignment on the substitution method one… it’s a sensible decision but aesthetically I liked the way it was, whether that’s a good choice or not.

Also you might like the new footnote I added:

[fn:lexical-scope-happens-here] This is where the choice is made
between lexical and dynamic scoping.  The environment which is
extended is not the environment of the caller, but the environment of
the previous expression in which this lambda was defined... this is is
how we achieve the functionality described in the =closures= section.

In a sense, "lexical scope" is "scope is defined by capturing where it
is written" and is capability secure, is explicit, and preserves the
"if you don't have it, you can't use it" property.  "Dynamic scope" is
instead "scope is defined by the invoker" (and their parent invokers,
all the way up the stack of current invocations) and is implicit, but
also ambient including in the ambient authority sense, making dynamic
scope suffer more serious security issues (and not coincidentally,
more strongly resemble access control list systems).
1 Like

Final editorial decisions are always the authors’. I’m glad the feedback was useful.

The footnote is helpful and, I think, informative. There is a small typo:

Oops! Thanks on that. Fixed in git… and I’ll fix in the next website export/push, probably tomorrow. Thanks!

1 Like

I pushed the head of main to the website.

Thanks to Florian Pelz, Our Scheme Primer is now available in German! (HTML) (PDF) (ODT) (ORG) (TEXI) (EPUB) (source)