SICP in Doom Emacs
One of the things I would like to do this year is to improve my foundations in computer science. In order to accomplish this, I’m working my way through the fascinating “Structure and Interpretation of Computer Programs”, by Abelson, Sussman, and Sussman. The book is freely available online in a variety of formats, including HTML and a beautifully laid out and formatted PDF (GitHub repo).
Here is the way I’ve setup my Doom Emacs for studying this book, experimenting with code, and taking notes (with org-mode
). I had to piece together this setup from various sources online, this is what’s worked for me.
These instructions are specific to macOS.
Install Racket and the SICP lang
The programming language used in SICP is MIT Scheme, but it has significantly evolved since the book was written. Luckily, Racket, a modern scheme implementation, supports custom DSLs, one of which can be used to emulate the version of Scheme used in SICP.
Racket
Install Racket via Homebrew. I chose the minimal-racket
formula, as prefer to write code in Emacs and did not want to install DrRacket (an IDE).
$ brew install minimal-racket
This will make the racket
command available, which will open a Racket REPL.
SICP language
Racket provides “SICP Collections”, which make Racket compatible with the MIT Scheme implementation that was in use at the time of the book’s publication. When you’re not using DrRacket, this can be installed via the Racket package manager, which you’ve conveniently also installed in the previous step:
$ raco pkg install sicp
Once this is installed, we have everything we need on the system side, and it’s time to move on to the Emacs side.
Doom Emacs
I’m using Doom Emacs, so these steps assume you do too. If you’re using you own config, I would recommend that you check out Konstantinos Chousos’s SICP in Emacs post, which also has some useful additional info, such as how to read the book in the Texinfo format.
We will install support for Racket, create an org file for our notes, and make sure that the code blocks of our org file use the SICP language rather than plain Racket.
init.el
In your Doom Emacs init.el
file (located in your Doom config directory, in my case at ~/.config/doom/init.el
), uncomment the scheme
line under the :lang
header, and add the +racket
flag to it, like this:
;; ~/.config/doom/init.el
(scheme +racket) ; a fully conniving family of lisps
Reload your config by hitting SPC h r r
(or restarting Emacs, if you’re so inclined). This will install Geiser along with geiser-racket, which will allow you to open a Racket REPL, evaluate Racket code blocks in Org, etc.
Geiser
Optionally, we need to be able to tell Geiser about the fact that we want the SCIP lang to be enabled when we open a Racket REPL. This can be accomplished by adding the following line to ~/.racket-geiser
:
;; ~/.racket-geiser
(require sicp)
This is optional. We might not want to do this if we work with Racket code outside of the SICP context, which I don’t, so I set it up this way.
If we don’t do this, we need to add (require sicp)
on the first line of each of our Org code blocks that use SICP syntax. Alternatively, if we are working with Racket source files rather than Org code blocks, we need to add #lang sicp
as the first line of each file in which we wish to work on SICP code.
Org mode
I take notes in Org mode. The main benefit of doing this is that I can insert code blocks that can be evaluated inline by pressing C-c
, for example as such:
#+begin_src scheme
(define (square x) (* x x))
(define (sum-of-squares x y)
(+ (square x) (square y)))
(define (f a)
(sum-of-squares (+ a 1) (* a 2)))
(f 5)
#+end_src
#+RESULTS:
: 136
For this to work properly, I have added the following header to the top of my notes file:
#+property: header-args:scheme :cmd "racket" :results value :session sicp
This tells Org the following things about how to work with Scheme code blocks:
- Use the command
racket
to start the underlying REPL - Use the value of the last expression in the
#+RESULTS:
block - Keep a REPL session named “sicp” running for this document
This last option means that blocks are not isolated, so a procedure defined in one block will be also available in all the following blocks, and will not need to be re-defined each time. Convenient!
This should be enough to get you started with SICP in Doom Emacs. Please let me know if you run into any trouble, or if any of these instructions can be improved! Godspeed.