Scheming a mise-en-abîme in BQN (WIP)

Prelude

We will build and interpreter for a subset of the Scheme programming language, following a Peter Norvig's essay. An alternative reference would have been of course SICP's metacircular evaluator1, but I consider lispy to be a very elegant implementation targeting a non-Lisp host2.

A R5RS dialect

Our goal is to adhere to the Revised\(^5\) Report on the Algorithmic Language Scheme (R5RS). However, seasoned schemers will quickly notice that our implementation still has quite some distance to cover in reaching full compliance. Let's start by defining some utilities. It is sad that the 1-modifier is needed, after all, Booleans are not that special.

_bool ← {𝔽◶"#f"‿"#t"}

A global environment:

env ← ⟨
  "sin", "cos", "tan", "asin", "acos", "atan",
  "log", "+", "-", "*", "/", ">", "<", ">=", "<=", "="
  "abs", "append", "apply", "begin", "car", "cdr", "cons"
  "eq?", "expt", "equal?", "length", "list", "list?"
  "map", "max", "min", "not", "null?", "number?"
  "print", "round", "symbol?"
⟩ •HashMap ⟨
  ⋆⁼, +´, -´, ×´, ÷´, >´, <´, ≥´, ≤´, =´
  |, ∾´, {𝕎𝕩}´, {𝕩}, ⊑, 1⊸↓, ⋈´
  ≡´_bool, ⋆´, =´_bool, ≠, ⋈, 0⊸=_bool{•Type•BQN⎊1𝕩}
  {𝕎¨𝕩}´, ⌈´, ⌊´, 0⊸≠_bool¬, @⊸=_bool, •BQN⎊1
  •Show, ⌊0.5+⊢, 2⊸=_bool{•Type⊑𝕩}
⟩ ∾˜ •math •ns.Get¨ "sin"‿"cos"‿"tan"‿"asin"‿"acos"‿"atan"

The interpreter:

Scheme ← {
  T ← ' '=(-⟜1·+`·¬⊸∧⟜»⊸∨·+˝"( )"=⌜⊢)⊸⊔
  T𝕩
} ⋄ Scheme "(begin (+ 1 1) (* (+ 3 2) 1) (define a (+ 3 3)))"

A Lisp quine

Given the title of this post, it seems only fitting to test our interpreter with a quine:

Scheme "((lambda (x) (list x (list (quote quote) x)))
         (quote (lambda (x) (list x (list (quote quote) x)))))"
"((lambda (x) (list x (list (quote quote) x)))
         (quote (lambda (x) (list x (list (quote quote) x)))))"

Naturally, we can do more rigorous tests by comparing to my favorite Scheme implementation3. To achieve this, we'll leverage BQN's foreign function interface:

ch ← "../supp/chicken/libchicken.so" •FFI "*u8"‿"eval_scheme"‿">*u8:c8"
R5RS ← {@+𝕩.Read¨ ↕1⊸+•_while_(0≠𝕩.Read)0}Ch∾@

But fear not, there’s no room for monotony here. After all, people much prefer dealing with machinery to dealing with bureaucracies4:

("Not Compliant"⊸!Scheme≡R5RS)¨ "(+ 10 122)"‿"(* 4 2)"
⟨ ⟨ "(+ 10 122)" "132" ⟩ ⟨ "(* 4 2)" "8" ⟩ ⟩

Footnotes:

1

I recommend SICP as further reading. Much like Louis Reasoner, I attempted solving all the problems in the book, but I haven't gotten very far. I believe there are some interesting Racket bits in my solutions, though.

2

I am not alone in this view; for instance, the Lizard Book dedicates an entire section to it.

3

One of my favorite hacker guidelines is The Brutalist Programming Manifesto, written by the creator of Chicken Scheme.

4

John McCarthy, 1986.