Don't Panic!
aurellem ☉
1 Welcome
Welcome to 6.945/6.S081, 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-scheme
and either edwin or
emacs, two very similar editors.
2 Install mit-scheme
First off, get access to GNU/linux system. You can either use the
Athena machines, or your own system. While it is certainly possible
to install mit-scheme
and edwin/emacs on windows and macs, we
don't offer support for those systems.
You have two options when it comes to getting access to the implementation of scheme (mit-scheme) that we need for the class.
2.1 Use Athena
- Advantages:
- easiest option
- Disadvantages:
- requires internet connection or physical presence at an Athena cluster.
Just log onto your MIT Athena account and execute:
add 6.945
Now you have access to mit-scheme
.
If you type
which mit-scheme
You will see that mit-scheme is now provided by the 6.945 Athena course locker.
Remember that 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 mac users, you can just use ssh.
2.2 Install mit-scheme
binaries on your own system
- Advantages:
- Use your own computer
- Disadvantages:
- Slightly more complicated than Athena
Go to the mit-scheme
project website here:
http://www.gnu.org/software/mit-scheme/, and download the
appropriate binary package for your system. If you don't know
whether you to pick the "i386" or "x86-64" option, run
uname -m
To determine what type of processor you are using.
In order to install the software, you should choose a directory on
your system where you would like to put the files you download, and
another directory where you will place the final product after you
have compiled everything. One common place to put these files is
/usr/local/
. Here is a transcript of when I installed mit-scheme
on my 64 bit GNU/Linux system for reference.
# I like to put the compiled scheme files inside the directory I use # for the class. Another reasonable option would be to use some # temporary directory for SCHEME_DOWNLOAD and /usr/local for # SCHEME_INSTALL SCHEME_DOWNLOAD=~/6.945 SCHEME_INSTALL=~/6.945/artifacts mkdir -p $SCHEME_DOWNLOAD cd $SCHEME_DOWNLOAD # for 32 bit GNU/Linux system, use mit-scheme-9.1.1-i386.tar.gz # instead of mit-scheme-9.1.1-x86-64.tar.gz here. wget -c http://ftp.gnu.org/gnu/mit-scheme/\ stable.pkg/9.1.1/mit-scheme-9.1.1-x86-64.tar.gz tar xf ./mit-scheme-9.1.1-x86-64.tar.gz cd ./mit-scheme-9.1.1/src # This prepares the build system for scheme and tells it to install # the binaries that will be created to SCHEME_INSTALL ./configure --prefix=$SCHEME_INSTALL # This does the actual building of mit-scheme make -j9 compile-microcode # And this copies the installed files to SCHEME_INSTALL make install # try out your new mit-scheme system cd $SCHEME_INSTALL/bin ./mit-scheme --version
You should see something like:
MIT/GNU Scheme running under GNU/Linux Type `^C' (control-C) followed by `H' to obtain information about interrupts. Copyright (C) 2011 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 Monday January 20, 2014 at 3:00:50 AM Release 9.1.1 || Microcode 15.3 || Runtime 15.7 || SF 4.41 || LIAR/C 4.118 Edwin 3.116
3 Get an Editor
There are two editors we support in the class: edwin and emacs. In
contrast to other editors, both edwin
and emacs
are highly
programmable – they empower 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
- slightly more difficult to set up for 6.945 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 Installing Edwin
If you chose edwin
, then you don't really have to do anything – it
comes with mit-scheme
. If you're on Athena, and have added the 6.945
course locker, you can start edwin by executing
edwin
If you're on your own system, you can start edwin by executing
mit-scheme --edit
If the mit-scheme binary is not on your PATH, you'll have to type in
the full path to the mit-scheme binary on your system. On my system, I
installed mit-scheme to /home/r/proj/6.945/scheme
, so I use
/home/r/proj/6.945/scheme/bin/mit-scheme --edit
to start edwin.
You can easily make an "edwin" command on your own system by adding an
alias to your ~/.bashrc
file. Add something like the following line
to your system:
alias edwin="mit-scheme --edit"
You may also want to increase the heap size to get better performance. For 32 bit systems, use:
mit-scheme --edit --heap 10000
For 64 bit systems, you can use:
mit-scheme --edit --heap 100000
3.3 Installing Emacs
If you are on Athena, then emacs
is already installed and ready to
use. If you are running Ubuntu, execute:
sudo apt-get install emacs
If you are running arch linux, execute:
sudo pacman -S emacs
Otherwise, check your distribution's package repository and use the recommended emacs package. If you're using windows, the following might be helpful http://ftp.gnu.org/gnu/emacs/windows/.
3.4 Customize your Editor
Neither emacs
nor edwin
are that fun to use without
customization. Each editor reads a config file when it starts up, and
executes the code in that config file. For emacs, this is a file in
your home directory called .emacs
, written in elisp
. For edwin,
this is a file in your home directory called, you guessed it,
.edwin
, written in scheme.
It can be very daunting to develop your own custom "dot-file" for these editors, so here are some settings to get your started.
3.4.1 Emacs dot-file
In addition to a file called .emacs
in your home directory, emacs
also uses a directory in your home directory called .emacs.d
to
store related files. Our default settings for 6.945 provide layouts
for both .emacs
and .emacs.d
.
6.945 provides you two options for configuring emacs : a "basic" setup and an "extra" setup.
The "basic" setup contains just those things that you need to use scheme, along with a few other functions for manipulating fonts and printing your buffers.
The "extra" setup contains everything in the "basic" setup, along with several color modes, a terminal emulator, and a few other things.
To get started with emacs, first download our emacs setup file:
Here is a transcript for installing the "extra" emacs config.
wget http://web.mit.edu/6.945/dont-panic/emacs-extra-config.tar.bz2
tar xvf emacs-extra-config.tar.bz2
cd emacs-extra-config
make install
If when you execute
make install
make
tells you that ~/.emacs.d
or ~/.emacs
already exist, then
you should check to see if they have anything important that you want
to keep.
If you don't care about your previous emacs settings, you can run
make remove-emacs-config
to delete whatever default settings you may have. You can also use this to start over if you ever mess up your emacs config and want to reset everything.
Be sure not to do this if you want to keep your current emacs settings! If you already have settings you like, feel free to pick and choose from the files and configurations available in the archive file.
Finally, you should edit ~/.emacs
and replace the line:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;; MIT-scheme config ;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This is the place where you have installed scheme. Be sure to set ;; this to an appropriate value!!! (setq scheme-root "/mit/6.945")
to refer to the proper path to your mit-scheme
install. For Athena,
this is /mit/6.945
(and is already configured for you). If you
installed scheme on your own system, it is the directory you used for
$SCHEME_INSTALL
.
3.4.2 Edwin dot-file
Edwin has a lot less configuration options available than emacs, because there are less library files available. Here the settings Sussman and myself use:
http://web.mit.edu/6.945/dont-panic/.edwin
They provide firefox-like font resizing and some good default colors.
To install these settings for yourself, simply place the .edwin
file
in your home directory.
cd ~
rm -f .edwin
wget http://web.mit.edu/6.945/dont-panic/.edwin
3.5 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 always see the available key commands by executing:
C-h m
This will tell you all the commands available in your current mode.
Now go do that tutorial!
3.6 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 t
- If you don't know how to use the basic navigation functions, use this to enter an interactive tutorial that will show you the ropes.
- 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.
4 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.
To start a REPL in emacs, execute:
M-x run-scheme
In edwin, you already have a REPL running in the scheme buffer.
4.1 REPL
tutorial
You can try using the REPL
right now! First, create two buffers:
one with a mit-scheme
REPL
and one displaying an empty scheme
file. The file should end in ".scm" so that emacs=/=edwin
can
recognize that it is a scheme file and provide syntax
highlighting and REPL integration.
Go to the REPL
, 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
;;;; Fibonacci Numbers (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
. 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.
4.1.1 Note on comments
In scheme, the ; character is the comment character. But historically, the number of ; characters used has meaning. Four ;'s means that this comment is the title or header of the file. Three ;'s means the comment should be left justified. Two ;'s means that the comment should be indented as if it was code, and a single ; means that the comment should be right justified.
There is also the #| ... |#
multi line comment, similar to the
/** ... **/
comment in C
and C++
. This comment is useful for
including test cases. If you were completing the definition of
fib
for a pset, you might use a multi-line comment to include
test cases like so:
;;;; Fibonacci Numbers (define (fib n) ;; Calculate the nth Fibonacci number recursively (if (< n 2) 1 ; base case (+ (fib (- n 1)) (fib (- n 2))))) #| (fib 5) ;Value: 8 (fib 20) ;Value: 10946 |#
Note that use can evaluate the (fib 5)
and (fib 20)
scheme
forms using M-z or C-M-x even though they are in comments.
5 Debugging scheme code
Many problems are transparent if you have an interactive
debugger. Instead of littering your code with display
statements,
you can examine the values of local variables while your function is
running.
5.1 Start the debugger
You can always start the debugger by evaluating
(debug)
at a scheme REPL. 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 familiarize yourself with the different
options.
5.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 attempt 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 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.
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> (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 do-loop (begin (if (queue-empty? queue) (let ((environ ... 7 loop (loop (bind-abort-restart cmdl (lambda () (der ...
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
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!