Don't Panic!
Table of Contents
- 1. Welcome
- 2. Getting
MIT/GNU Scheme
- 3. Getting an Editor
- 4. Exploring
MIT/GNU Scheme
- 5. Customizing your Editor
- 6. Exploring your Editor
- 7. Workflow in 6.945
- 8. Debugging scheme code
Written by rlm, larsj, lgilpin, kclisp
Updated for Spring 2020
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.
Don't hesitate to email kclisp@mit.edu if you are having difficulty getting started.
2 Getting MIT/GNU Scheme
First off, get access to a GNU/Linux system. You can either use the
Athena machines, or your own system. While it is certainly possible
to install MIT/GNU Scheme
and edwin/emacs on Windows and Macs, we
don't offer support for those systems.
You have three options when it comes to getting access to the implementation of scheme (MIT/GNU Scheme) that we need for the class.
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 inter rupts. Copyright (C) 2019 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 August 10, 2019 at 6:28:48 PM Release 10.1.10 || Microcode 15.3 || Runtime 15.7 || SF 4.41 LIAR/x86-64 4.118 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 the version of mit-scheme
is >=10.1.10.
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
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 (>=10.1.10).
Note about Mac Support: http://www.gnu.org/software/mit-scheme/ provides a pre-packaged Mac OS X application binary that includes MIT/GNU Scheme and a Mac GUI version of Edwin. Section 2.3.2 describes installation instructions for this binary. Alternatively, 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.
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. To determine
your computer architecture (either i386 or x86-64), run:
uname -m
You are probably using a 64-bit architecture.
Then follow the instructions here: https://www.gnu.org/software/mit-scheme/documentation/mit-scheme-user/Unix-Installation.html
2.3.2 Using a pre-compiled Mac Binary
Download the OS X Binary from http://www.gnu.org/software/mit-scheme/. Open the .dmg disk image and copy the MIT/GNU Scheme application to the Applications folder.
To avoid complications with slashes and spaces in the application name, rename this application bundle from MIT/GNU Scheme to MIT-Scheme:
cd /Applications mv MIT\:GNU\ Scheme\ 10.1.10.app MIT-Scheme.app
Depending on the configuration of your Mac, you may be prompted to install the X windows system. This is available as XQuartz on Mac 10.6+ at http://xquartz.macosforge.org.
With an X window system installed, Double-clicking the resulting mit-scheme application should load an Edwin editor.
Finally, to provide command-line access to mit-scheme similar to
that on a GNU/Linux machine or Athena, add a new alias to the Mac bash
configuration file. Provided you renamed the application to
MIT-Scheme.app as described above, add the following to
~/.bash_profile
:
alias mit-scheme="/Applications/MIT-Scheme.app/Contents/Resources/mit-scheme"
When you restart the terminal, typing mit-scheme
should start the
Scheme REPL.
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 youredwin
related problems
- entirely written in
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
The version of emacs doesn't really matter. After getting access to emacs, run it with:
emacs
3.3.1 Use Athena
If you are on Athena, then emacs
is already installed and ready to
use.
3.3.2 Install emacs
from GNU/Linux distribution repositories
Use your distribution's package manager to 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:
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:
5.2.2 My Init File
You can get a simplified version of my init file here:
I use the paredit and auto-complete packages, 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
In edwin
or emacs
, 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.
Then type:
C-x 3
to split the window side-by-side.
To switch from screen to screen, type:
C-x o
In emacs, type:
M-x run-scheme
to start scheme
.
7.2 REPL
tutorial
You can try using the REPL
right now!
Go to the REPL
and type:
(fib 5)
And press <enter>.
You will see that you get an error, because the variable fib
is not yet defined.
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 C-M-x
(in emacs) or M-z
(edwin) 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!