Skip to content

A: Core Evaluation Models for Scheme

VermillionAzure edited this page Jan 20, 2018 · 1 revision

Introduction

How might one implement Scheme?

Scheme is considered a member of the greater Lisp programming language family, but it diverges from it in a few majors ways:

  • Macros - Lisp-expression based macros have been around for quite a long time, but many forms of it have existed over its history: defmacro for procedural macros, syntax-case macros, and declarative syntax-rule macros. Currently, Scheme has settled on the declarative, pattern-matching based syntax-rule macros.
  • "Lisp-1" style namespacing - Unlike Common Lisp, another major branch of the Lisp programming language family, Scheme places every variable in a common namespace -- this means that functions and variables names must share the same pool of name possibilities to choose from.
  • First-class undelimited continuations - Many concepts share the name "continuation," from the procedures that definite continuation-passing style (CPS) intermediate representation (IR) to undelimited continuations (call-cc) to delimited continuations (shift/reset). Scheme (R7RS) supports the call-with-current-continuation model for continuations, which is powerful, but relatively costly to implement.
  • Functional language design - Scheme's language design is purposely made to support functional programming and make mutation/side-effects explicit by the side-effect! naming convention. The result? One can go through the exercises in Structure and Interpretation of Programming Languages with an entirely functional subset of Scheme, and then introduce side-effects as a separate part of it.

Common Misconceptions

Scheme can use recursive evaluation

  • Scheme cannot be evaluated with a purely recursive evaluation model. The symmetry of the "read/eval" recursion that one might find in simpler Lisp designs is explicitly broken by the presence of Scheme's undelimited first-class continuations. The result? One must find a way to explicitly save the state of your evaluation model and restore it as a first-class feature of your chosen representation.

Is this supported by C or C++ as a native feature?

  • Saving and restoring the state of the stack is not explicitly supported as a first-class feature in the C or C++ standards. This is due to the flexibility that both languages wish to give to implementations on different architectures. It is entirely possible to try and do this in native code by actually saving and restoring the memory state of the stack through pointers, but it is undefined behavior, as explored by Bigloo Scheme's work with integrating LLVM.

  • Interop between C and Scheme code even in the presence of call/cc has been achieved with setjmp/longjmp with Chez Scheme.

Complex numbers are mandatory for a Scheme implementation

  • They are not, according to R7RS.

Lists are never circular

  • The standard is mostly silent on this, but the presence of circular lists is explicitly hinted at in the design requirements of certain functions that must ensure they have correct functionality even with the presence in circular lists
    • One example: datums that contain circular references and read.

Scheme macros do not support static scoping

  • Due to how the current syntax-rules is defined in the standard, macros capture the scope of their definition. This means that scopes can be assigned to macros to statically decide the bindings of names to scopes. This is exemplified by Racket's macro system, which, at the time of writing, was recently overhauled to take advantage of this with syntax objects.