Skip to content

Latest commit

 

History

History
239 lines (160 loc) · 9.24 KB

README.md

File metadata and controls

239 lines (160 loc) · 9.24 KB

SICP Study

This repository is my study of Structure and Interpretation of Computer Programs and its lectures. The code is written in R6RS Scheme, tested with Chez Scheme, Guile, and Racket.

For more information, see the website.

Exercises

Usage

Use ./run.sh chez, ./run.sh guile, or ./run.sh racket depending on your Scheme implementation.

To see the options, pass --help. For example, ./run.sh chez --help.

Racket produces artifacts in compiled/ directories. To remove them, run make clean.

Structure

The program starts in main.ss. Each chapter of the book has its own file in src/sicp/, written in a domain-specific language implemented in src/lang/core.ss. Source files in src/compat/ reconcile differences between the supported Scheme implementations.

Language

Tests use =>, ~>, =?>, =$>, =!>, and =>...:

(+ 1 2 3) => (+ 3 2 1) => 6            ; => asserts equality

(+ 1.0 0.1) ~> (- 1.2 0.1) ~> 1.1      ; ~> allows a small margin of error

(random 5) =?> [0 1 (+ 1 1) 3 4]       ; =?> is for nondeterministic tests

(display "hi") =$> "hi"                ; =$> "..." tests standard output
(display "hi\nbye\n") =$> ["hi" "bye"] ; =$> [...] splits lines

(error 'foo "bad" 3) =!> "foo: bad: 3" ; =!> tests the error message
(error 'foo "bad" 3) =!> "bad"         ; any substring will do

(let loop () (loop)) =>...             ; =>... asserts nontermination

Code fragments are isolated to their part of the book:

(Chapter :1 "chapter title") ; The ":" sigil is for the text

(define a 1) ; This belongs to Chapter 1

(Section :1.1 "section title")

(define b 2) ; This belongs to Section 1.1

(Section :1.1.1 "subsection title")

(define c 3) ; This belongs to Subsection 1.1.1

(Exercise ?1.1) ; The "?" sigil is for exercises

(define d 4) ; This belongs to Exercise 1.1

We can import definitions out of order:

(Section :1.1 "First section"
  (use (:1.2 square)))   ; import square from Section 1.2

(define nine (square 3)) ; ok
(define eight (cube 2))  ; ERROR, 'cube' not defined

(Section :1.2 "Second section")

(define (square x) (* x x))
(define (cube x) (* x x x))

(Exercise ?1.15
  (use (:1.2 cube square)))

(define a (+ (square 3) (cube 4))) ; ok

We can also unhygienically paste code, but only from earlier sections in the same file:

(Section :1 "Original")

(define a 1)
(define (inc x) (+ x a))
(inc 42) => 43

(Section :2 "Copy")

(define a -1)
(paste (:1 inc))
(inc 42) => 41

For more details, see A Note on the Language.

Notes

Study notes are stored in notes/text.md and notes/lecture.md. They are written Pandoc Markdown, with some extras implemented by the website generator:

  • Heading labels: # 1A: Foo, ## 1.2: Bar.
  • LaTeX math: inline $...$, display $$...$$.
  • Internal links: [](@1.2.3) (Section 1.2.3 of the textbook), [previous lecture](@2b) (Lecture 2B), [](:1.2) (Section 1.2 in the exercises), [](?1.23) (Exercise 1.23).
  • Citations: [@1.2.3] (Section 1.2.3 of the textbook), [@1.2.fn42] (footnote 42 on the Section 1.2 page), [@1a.p3] (page 3 of the transcript for Lecture 1A).
  • Code blocks implicitly receive the scheme language class.
  • Quotes wrapped with ::: highlight/::: go on the Highlights page.
  • Ranges like 1.1-6 wrapped with ::: exercises/::: produce a list of exercise links.

Website

In addition to the notes and exercises, this repository contains a custom static site generator. Its output is stored in docs/ and served on https://mk12.github.io/sicp by GitHub Pages.

The website is pure HTML5 and CSS. It contains no JavaScript.

Usage

To build the website, make sure you have all the dependencies and then run make docs. A separate process builds each HTML file, so you can significantly speed this up by parallelizing, for example make docs -j10.

To view the website, open docs/index.html in your browser.

Use ./watch.sh to live-reload the website while you edit sources.

Implementation

The generator starts in docgen.c. It semi-parses Markdown and Scheme, and renders things like navigation links, headings, and tables of contents. It then forks to Pandoc, which runs filter.lua. The Lua filter deals with internal links, citations, code blocks, math, and diagrams.

To render math and diagrams, the Lua filter communicates over a Unix socket with the render.ts server (described below). It uses the C library ntsp.c to do this, loaded from a .so file. We therefore require Pandoc to be dynamically linked to libc; the fully static builds provided for Linux will not work.

The render.ts server is a Deno server implemented in render.ts. It serves requests in a simple text-based protocol over a Unix socket. It renders math using KaTeX, and converts ASCII diagrams to SVG using svgbob and svgo. The benefit of this approach, rather than invoking these tools directly in the Lua filter, is that it avoids spawning a new process for every piece of inline math.

To highlight code, the Lua filter uses the C library schemehl.c. I wrote this library to highlight the way I want, including proper handling of quasiquotes.

Pandoc assembles the result using template.html. The template embeds SVGs from pandoc/assets/ rather than linking to them. (For SVGs that occur multiple times, it embeds them once at the top and then instantiates them with the <use> tag.)

Finally, docgen post-processes the HTML and writes it in docs/.

The pages are styled by style.css. It follows the BEM naming guide.

Contributing

Before submitting a PR, run make. This makes the following targets:

  • make lint: Lints Scheme, TypeScript, and Bash.
  • make fmt: Formats C, Objective-C, and TypeScript.
  • make docs: Builds the website.
  • make validate: Validates HTML.
  • make test: Tests with all Scheme implementations.

Style

This project follows http://community.schemewiki.org/?scheme-style, with some changes:

  • Disregard Rule 3: Closing parens close the line.
  • Limit all lines to 80 columns.
  • Insert one blank line between top-level definitions.
  • Use alignment spaces only at the beginning of lines, never within them.
  • Use ;; for normal comments, and ; for commented code/diagrams.
  • Use ; for inline comments. Separate from code by one space (or more for alignment).

Run make lint-ss to verify these rules.

Editor support

Run make clangd to create compile_commands.json for C/C++ LSP support.

Run make vscode to set up tasks for VS Code:

  • test: Run all tests using Chez Scheme.
  • lint: Lint all Scheme and Markdown files.

The test and lint tasks parse results into the Problems view, which you can advance through with F8.

Dependencies

Run ./deps.sh check to see if you're missing any dependencies, and (macOS only) ./deps.sh install to install them.

  • Chez Scheme, Guile, and Racket: Scheme implementations.
  • Pandoc: Used to build the website. Must be dynamically linked to libc.
  • Lua: Its headers are used by the libraries in tools/lua/.
  • Deno: Used to run a server that renders math and diagrams.
  • svgbob: Used to convert ASCII diagrams to SVG.
  • Python 3: Used for some scripts.
  • vnu: Used to validate HTML files.
  • clang-format: Used to format C files.

You also need a C compiler to compile lint.c and docgen.c.

License

Most of the source code in this repository is available under the MIT License.

Some files in src/sicp/, notes/, and docs/ are derivative works and are available under the CC BY-SA 4.0 License instead.

See LICENSE for details.