Don't Panic!

Table of Contents

Written by rlm, larsj, lgilpin, kclisp

Updated for Spring 2021

1 Welcome

Welcome to 6.945/6.905, Adventures in Advanced Symbolic Programming!

This is a basic guide to getting started with the programming tools we will be using in the class, which are MIT/GNU Scheme and either edwin or emacs, two very similar editors.

Sections 2, 3, 4, 6, and 7 are essential. Please follow these thoroughly.

Don't hesitate to email kclisp@mit.edu if you are having difficulty getting started. Also, please email if you have comments or find bugs.

2 Getting MIT/GNU Scheme

You can get access to MIT/GNU Scheme through three different methods. You only need to follow one of the three.

After running scheme, you should see something like this:

MIT/GNU Scheme running under GNU/Linux
Type `^C' (control-C) followed by `H' to obtain information about interrupts.

Copyright (C) 2020 Massachusetts Institute of Technology
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Image saved on Saturday January 30, 2021 at 6:30:15 PM
  Release 11.1 || SF || LIAR/x86-64

1 ]=> 

2.1 Use Athena

  • Advantages:
    • Very little setup required
  • Disadvantages:
    • Requires internet connection or physical presence at an Athena cluster.

Log in to your MIT Athena account. If you're at an Athena cluster, then skip this next step. If you're using your personal machine, then connect via ssh with:

ssh -Y [your_kerberos]@athena.dialup.mit.edu

You can always access Athena by using ssh from any operating system, so you can have the convenience of Athena and the convenience of using your own machine. For Windows, use PuTTY to access Athena. For Macs, you can just use ssh.

Now in your Athena account, to get access to the course's software, execute:

add -f 6.945

Now you have access to MIT/GNU Scheme, which you can run with:

scheme

2.2 Install MIT/GNU Scheme from package managers (GNU/Linux and MacOS)

  • Advantages:
    • Use your own computer
    • Easy to set up if the repositories have an up-to-date version of mit-scheme
  • Disadvantages:
    • Many distributions do not have up-to-date versions

Use your distribution's package manager to install mit-scheme.

Make sure that it is the latest version of mit-scheme (>=11.1).

2.2.1 Debian-based distributions (Debian, Ubuntu, Mint, etc.)

If you're running LTS distributions, then the scheme version is likely out-of-date.

sudo apt-get install mit-scheme

Also install the debug package (so that pp works):

sudo apt-get install mit-scheme-dbg

2.2.2 Arch-based distributions (Arch, Manjaro, etc.)

sudo pacman -S mit-scheme

2.2.3 MacOS (with Homebrew)

brew install mit-scheme

2.3 Install MIT/GNU Scheme binaries on your own system

  • Advantages:
    • Use your own computer
  • Disadvantages:
    • More complicated to set up

Be sure to download the latest version (>=11.1).

Note about Mac Support: If you have the correct tools (XCode, make, etc.), the "Unix Binary" can be downloaded, compiled and installed on Mac with only slight variations of the instructions in Section 2.3.1. According to https://www.gnu.org/software/mit-scheme/, "it is easy to generate a macos application from our normal distribution: after running make, run make macosx-app. Instead of running make install, just move mit-scheme.app to /​Applications/ (or wherever you want)."

Note about Windows Support: While it is certainly possible to install MIT/GNU Scheme and edwin/emacs on Windows, we don't offer support for those systems. Look into using the Windows subsystem for Linux or a VM.

2.3.1 Install on a GNU/Linux system

Go to the MIT/GNU Scheme project website here: http://www.gnu.org/software/mit-scheme/, and download the appropriate binary package for your system. Then follow the instructions here: https://www.gnu.org/software/mit-scheme/documentation/stable/mit-scheme-user/Unix-Installation.html

3 Getting an Editor

There are two editors we support in the class: edwin and emacs. In contrast to many other editors, both edwin and emacs are highly programmable – they allow you to change the editor to suit your particular needs. Each editor is almost entirely programmed in its own extension language: mit-scheme for edwin, and a dialect of LISP called elisp for emacs. What you make of these editors is limited only by the bounds of your creativity.

3.1 Which editor should you use?

  • edwin
    • entirely written in mit-scheme (you can extend it using stuff you learn in 6.945)
    • offers a better integrated scheme debugger than emacs
    • based on an older version of emacs (version 19) and has not been developed much since.
    • fairly anemic library – edwin is probably not that good a choice for editing python code, for example.
    • no online presence or community
    • Prof. Sussman uses edwin and he can help you with your edwin related problems
  • emacs
    • MUCH larger online community than edwin. If you get stuck on something there is likely someone on the internet who has already developed a solution.
    • Vast library of already-written code to customize emacs for almost any usage. org-mode alone is one of the many additional tools that comes with emacs that might make you want to consider it over edwin.
    • Still in active development, so is more "modern" than edwin, including things like Unicode support and integration with almost every language and version control system.
    • uses elisp, a fairly kludgy dialect of lisp, as an extension language
    • not as much integration with mit-scheme than edwin
    • I use emacs and can help you with your problems

Edwin is well suited for learning scheme and has been a traditional part of 6.001 and 6.945 at MIT for decades. If you choose it you'll be using a system that was specifically created to empower you to hack mit-scheme, whether you're a novice or an expert.

If you choose emacs, then you'll be putting in time learning an editor that many expert programmers consider to be the best programming tool in the world. It is likely that you will be able to use emacs for programming projects outside of 6.945, and for many more use cases than writing code in mit-scheme.

We support both editors in 6.945.

3.2 Getting Edwin

If you chose edwin, then you don't really have to do anything – it comes with mit-scheme. You can start edwin with:

mit-scheme --edit

3.3 Getting Emacs

You can get access to emacs through three different methods.

The version of emacs doesn't really matter. After getting access to emacs, run it with:

emacs

3.3.1 Use Athena

emacs is already installed and ready-to-use.

  1. From MacOS

    If you are sshing from MacOS, you may need to install the X windows system. This is available as XQuartz on Mac 10.6+ at http://xquartz.macosforge.org.

    Or you can also start emacs without using X windows.

    emacs -nw
    

3.3.2 Install emacs from package managers (GNU/Linux and MacOS)

Use your distribution's package manager to install emacs.

  1. Debian-based distributions (Debian, Ubuntu, Mint, etc.)
    sudo apt-get install emacs
    
  2. Arch-based distributions (Arch, Manjaro, etc.)
    sudo pacman -S emacs
    
  3. MacOS (with Homebrew)
    brew install emacs
    

3.3.3 Install emacs on your own system

Follow the instructions here: https://www.gnu.org/software/emacs/download.html

4 Exploring MIT/GNU Scheme

4.1 Discovery

Scheme has functions to inspect itself. You can execute apropos on a symbol to find all the bound names in the environment containing that string. For example:

(apropos 'vector)

finds all the bound names with "vector" in their name.

You can also get the source for a function using pp, as in:

(pp +)

What's the source of apropos and pp?

5 Customizing your Editor

Neither edwin nor emacs are that fun to use without customization. Each editor reads a configuration file (called init file) when it starts up, and executes the code in that init file. For edwin, this is a file in your home directory called .edwin, written in scheme. For emacs, this is usually in ~/.emacs.d/init.el, written in elisp.

It can be very daunting to develop your own custom init file for these editors, so here are some settings to get you started.

5.1 Edwin init file

Edwin has a lot less configuration options available than emacs, because there are less library files available. Here are the settings that Sussman uses:

.edwin

They provide firefox-like font resizing and some good default colors.

5.2 Emacs init file

Emacs has many configuration options. As you use Emacs more and more, your init.el will become more customized to your uses. There are also many packages available through MELPA.

5.2.1 MELPA Packages

MELPA is a repository for Emacs packages. Follow the instructions here to install it:

https://www.emacswiki.org/emacs/MELPA

5.2.2 My Init File

You can get a highly simplified version of my init file here:

init.el

I use the paredit package, which you can get from MELPA (Paredit is very useful!).

6 Exploring your Editor

Both edwin and emacs provide excellent, self-contained tutorials that will walk you through all the basic commands you need to know to use the editor.

To view the tutorial, execute:

C-h t

That means to hold down the CTRL key press the "h" key, release the CTRL key, then press the "t" key.

You can also print a reference card so that you can easily find many useful commands.

There are about a million things you can do with emacs; it's jokingly (or not so jokingly) said to be an operating system. For a tour of what you can do, go here:

https://www.gnu.org/software/emacs/tour/

Now go do that tutorial!

6.1 Discovery

How do you know what sort of things you can do in your editor? For example, how do you figure out that C-M-x will evaluate the scheme form at your cursor if you don't already know that? The answer is to use the following invaluable discovery commands:

C-h m
describes all the key bindings of the current mode you are using. You should read all the key bindings of both the scheme source code mode and the scheme REPL mode so you know what you can do.
C-h k
Each keyboard shortcut in emacs/edwin is bound to a longer, named function. If you know the keyboard-shortcut but don't know the name of the function the shortcut uses, this will tell you the long version if you enter the keyboard shortcut. (Question: what function does C-h k itself call?)
C-h v
This shows you the documentation of any variable and provides a link to the source.
C-h f
This shows you the documentation of any function and provides a link to the source.
C-h l
This displays the last 200 keystrokes you have typed. If you just accidentally did something cool and want to repeat it again, see what you typed with this.

Now seriously, use C-h m and take a look at all the different things you can do in your scheme mode and at the repl.

7 Workflow in 6.945

mit-scheme is part of a long tradition of computer languages in the LISP family of languages, which includes common lisp, clojure, elisp, maclisp, zetalisp, etc. LISP is almost as old as programming itself, having been created just a year after Fortran, the first "high-level" computer language.

The most important thing about programming using scheme, and any LISP for that matter, is to use the REPL.

REPL stands for Read Eval Print Loop, and it is similar to working at an interactive terminal where you enter commands, change your commands based on the results of previous commands, and save things for later use. REPL oriented programming stands in contrast to batch-based programming: instead of writing a program and then running/debugging it, you build your program piece by piece, playing with and changing each little piece as you construct them.

Generally, as you are programming in scheme, you will have one window which contains the code you are writing, and one window which serves as your REPL. You write some code (perhaps a single function), evaluate that code, then move over to the repl and experiment with the code you just wrote. Based on your repl interaction, you go back to your code and make changes, and then the cycle repeats. You can also run some tests in the REPL and then copy the results of those tests into your main source file, to use as documentation of what the function is supposed to do for certain inputs. This will be an effective way to prepare psets – you write code, then copy the answers to the problem from the REPL back to your source file.

First, let's get a minimal setup.

7.1 Minimal Setup

Let's get a scheme REPL and have two windows, one for the REPL and one for a scheme file.

If you are using edwin, then you automatically start with a REPL.

In emacs, start scheme by typing:

M-x run-scheme

In edwin and emacs, type:

C-x 3

to split the window side-by-side.

To switch from window to window, type:

C-x o

Finally, open a scheme file with:

C-x C-f

and type in the file name. The file should end in ".scm" so that emacs and edwin can recognize that it is a scheme file and provide syntax highlighting and REPL integration.

7.2 REPL tutorial

You can try using the REPL right now!

Go to the REPL and type:

(fib 5)

Press C-x C-e (edwin) or <enter> (emacs) to evaluate the expression.

You will see that you get an error, because the variable fib is not yet defined. Get out of the error with C-c C-c.

Now go to your scheme file and define fib with

(define (fib n)
  ;; Calculate the nth Fibonacci number recursively
  (if (< n 2)
      1                                 ; base case
      (+ (fib (- n 1)) (fib (- n 2)))))

While the cursor is inside this form, press M-z (edwin) or C-M-x (emacs) to evaluate the form and send it to the REPL. You can also press C-x C-e to evaluate the form to the left of the point. Now go back to the REPL and enter (fib 5) again and you will see the function you defined in your scheme file evaluated and printed to the screen. This is really cool! If this were a C or Java program you would have to write a small test-harness, re-compile and then run the program again to do what you have just done. As you work on building more complicated programs, you will begin to see the power of this method.

8 Debugging scheme code

Many problems are transparent if you have an interactive debugger. Instead of littering your code with pp statements, you can examine the values of local variables while your function is running.

8.1 Start the debugger

You can always start the debugger at a scheme REPL by evaluating

(debug)

When you do, you will see something like this:

There are 4 subproblems on the stack.

<stuff...>

You are now in the debugger.  Type q to quit, ? for commands.

2 debug> 

Try typing ? and familiarizing yourself with the different options.

8.2 Simple debugging walkthrough

Let's debug the following scheme function:

(define (factorial n)
  (if (< n 2) 
      1 
      (* n (factorial (dec n)))))

At first glance this seems to be a reasonable definition – we return 1 if we are given 1 as input, otherwise we return n times the factorial of n decremented by 1.

Evaluate this definition and then try to evaluate

(factorial 3)

at the REPL.

You will see:

1 ]=> (factorial 3)

;Unbound variable: dec
;To continue, call RESTART with an option number:
; (RESTART 3) => Specify a value to use instead of dec.
; (RESTART 2) => Define dec to a given value.
; (RESTART 1) => Return to read-eval-print level 1.

2 error> 

Whenever an error is encountered during the course of evaluating an expression, mit-scheme puts you into this mode. These options give some limited access to the debugger. You can either choose one of these options, type C-c C-c to exit from the error, or type (debug) to enter the debugger proper.

Here's an example transcript where I fix the problem of dec not actually being defined, and repair the original factorial call while it is still being executed.

2 error> (debug)

There are 8 subproblems on the stack.

Subproblem level: 0 (this is the lowest subproblem level)
Expression (from stack):
    dec
Environment created by the procedure: FACTORIAL

 applied to: (3)
The execution history for this subproblem contains 1 reduction.
You are now in the debugger.  Type q to quit, ? for commands.

Now that we're in the debugger, we can view the chain of procedure calls which led us to this situation.

3 debug> h
h
SL#  Procedure-name          Expression

0    factorial               dec
1                            ;undefined expression
2    factorial               (factorial (dec n))
3    factorial               (* n (factorial (dec n)))
4    %repl-eval              (let ((value (hook/repl-eval s-expression envi ...
5    %repl-eval/write        (hook/repl-write (%repl-eval s-expression envi ...
6                            (begin (if (queue-empty? queue) (let ((environ ...
7    loop                    (loop (bind-abort-restart cmdl (lambda () (wit ...

This is a stack trace like you might know from java or C. Each line in this list is called a subproblem, because scheme works by expanding and evaluating forms until it determines a value. Lines 4-7 are procedures involving the REPL itself. Line 3, (* n (factorial (dec n))), leads to the subproblem of figuring out what (factorial (dec n)) is, which leads to trying to evaluate (dec n) which is where our trouble starts.

We can view all the current bindings in the little environment created by the call to factorial. This is like exploring the values of local variables in any other debugger.

3 debug> a
a
----------------------------------------
Environment created by the procedure: FACTORIAL
Depth (relative to initial environment): 0
 has bindings:

n = 3


----------------------------------------
Environment named: (user)
Depth (relative to initial environment): 1


----------------------------------------
Environment named: ()
Depth (relative to initial environment): 2

This is a very simple environment, with only n, which is set to the value we entered into factorial, 3.

Let's fix the problem – dec isn't defined, but we want it to be equal to the function (lambda (x) (- x 1)). Using P in the debugger we can move out of the environment of factorial and back to the user environment, where we can define dec.

3 debug> p
p
Environment named: (user)
Depth (relative to initial environment): 1

3 debug> v
v

Evaluate expression: (define (dec x) (- x 1))

Value: dec

Now, we re-evaluate the original problematic subproblem and continue the original call to factorial.

3 debug> z
z

Expression to EVALUATE and CONTINUE with ($ to retry): $

;Value: 6

1 ]=> 

Note that if you are using edwin, you will be given an option to "start the debugger" in addition to the other options. If you start the debugger in this way, then you will get a very nice looking window that constantly displays many of the things you could otherwise access through the commands you have just been shown. Try it out; it's neat!

Author: Robert McIntyre, Lars Johnson, Leilani H. Gilpin, Kenny Chen

Created: 2021-03-07 Sun 19:31

Validate