3

Consider the following s-expression:

((lambda (car) (car (quote (a b c)))) cdr)

In most scheme implementations I've tried, this evaluates to (b c) because cdr is passed to the lambda, which names it car, taking precedence over the primitive implementation of car.

The Little Schemer provides an implementation of scheme written in scheme in chapter 10. That implementation returns a for the above expression, which seems incorrect to me.

It's clear why that implementation behaves that way: the names of primitive functions are treated as *const rather than *identifier here. A *const which is not a number or boolean is rendered as a primitive and this is eventually hardwired to the actual primitives.

I believe that the correct implementation would be to have no special detection of primitive names, but rather to create an initial table in the value function that contains an entry mapping the primitive names to the actual primitive implementations.

My question is: is this a bug in The Little Schemer's implementation of scheme? Is this behaviour well specified in scheme, or was it maybe not well specified in 1974 when the book was written?

Jeremy Huiskamp
  • 5,186
  • 5
  • 26
  • 19
  • AFAIK the little schemer doesn't use a specific Scheme implementation, please indicate _what_ version of interpreter (or library) you're using. – Óscar López Oct 31 '17 at 15:18
  • 1
    @ÓscarLópez Chapter 10 builds its own Scheme interpreter ([code](https://github.com/pkrumins/the-little-schemer/blob/master/10-value-of-all-of-this.ss)). That's the one that OP is asking about. – sepp2k Oct 31 '17 at 15:32
  • 1
    are you really reading the first edition? probably not, it was named Little Lisper, yes? I could never find it. – Will Ness Oct 31 '17 at 17:55
  • Nope, I've got The Little Schemer. I realize now that I misread the copyright in the book. It mentions 1974, but in reference to The Little Lisper. Now I'm curious what the algorithm in the original is :) – Jeremy Huiskamp Nov 02 '17 at 19:39

1 Answers1

3

Is it a bug?

The question whether it is a bug or not is to establish if the interpreter is supposed to follow Scheme scoping rules. Since you mention the year 1974 it is the year before the first Scheme report was posted, but many of the ideas were probably written about at the time and what was to become Scheme were small interpreters that probably were shared between research students with various subtle differences.

The little Schemer was originally called The little Lisper and worked under a Lisp later to become Common Lisp. When rewriting it to follow Scheme they tried to keep most of the code from earlier so it is likely the interpreter has different features than Scheme.

What the RNRS Scheme reports say

If the interpreter is to conform to the scheme reports it must allow for bindings to shadow the top level bindings. Here is a quote from the R5RS report about Variables, syntactic keywords, and regions

Every mention of an identifier refers to the binding of the identifier that established the innermost of the regions containing the use. If there is no binding of the identifier whose region contains the use, then the use refers to the binding for the variable in the top level environment

For later reports like the same section in R6RS top level is replaced with "definition or import at the top of the enclosing library or top-level program".

Sylwester
  • 47,942
  • 4
  • 47
  • 79
  • Is this behaviour not specified in the standard anywhere? I've been trying to browse through a couple of the reports, but having learned only what The Little Schemer teaches, I don't feel I have enough knowledge to interpret it accurately yet. – Jeremy Huiskamp Nov 01 '17 at 16:40
  • 1
    @JeremyHuiskamp According to the reports (all of them) a lexical runtime variable binding thrumps a top level ones. The interpreter is **not** a Scheme interpreter but rather a little scheme dialect. Eg. racket is a scheme dialect since it follows all but some aspects of the R5RS report. – Sylwester Nov 01 '17 at 18:20
  • Yeah, I realize the book describes a dialect, but for the most part, it explains where it departs, eg add1/sub1 instead of +/-, needing to define atom?, and obviously lots of stuff missing. But it's a bit different to diverge on a detail like this. Any chance you could point me at a specific spot in one of the reports that spells this out? – Jeremy Huiskamp Nov 02 '17 at 19:54
  • 1
    @JeremyHuiskamp Yes. "Every mention of an identifier refers to the binding of the identifier that established the innermost of the regions containing the use. If there is no binding of the identifier whose region contains the use, then the use refers to the binding for the variable in the top level environment" [R5RS](http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-6.html#%_sec_3.1) and [R6RS](http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-8.html#node_sec_5.2) version which adds import to the mix. – Sylwester Nov 02 '17 at 20:35
  • Thanks! The pointers to the spec are pretty much the answer that I was looking for. If you can edit it into your answer, or write a new one, I will mark that as accepted. I'm still curious about *why* it is the way it is. I suppose it's related to the book's non-scheme history... – Jeremy Huiskamp Nov 04 '17 at 14:02
  • @JeremyHuiskamp Like this? – Sylwester Nov 04 '17 at 15:01
  • Perfect! Thanks! – Jeremy Huiskamp Nov 04 '17 at 16:24