Colorado State University

Running Allegro Common Lisp From Emacs



Getting Started

A much more powerful alternative to running ACL from the Unix command line is to run Allegro Common Lisp (ACL) within one window of an Emacs screen. If you are not familiar with the rudiments of Emacs, you will want to look over the Emacs handout for this course before proceeding with the tutorial in this handout.

The advantages of running ACL from within Emacs are many. While the interface between ACL and Emacs is quite sophisticated and complicated, most of the complexity is hidden, and the sophistication will help you with many common operations. For instance, you gain the ability to type Lisp expressions into an editor buffer, using the full power of the editor to modify and change them, and with a single keystroke, have Emacs evaluate these expressions. In addition, documentation on functions, arguments to functions, and source files containing function definitions can all be called up with a single keystroke.

To run ACL from within Emacs requires that you `tell' Emacs how to connect to ACL. The means you will need to add some lines to your .emacs file for initializing Emacs. The complete listing of these commands follows. However, you need not retype all these commands. They can be found in the file allegro-dot-emacs-additions, but look exactly like:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;  The Hooks for using Allegro Common Lisp from within Emacs
  (setq load-path (cons "/usr/local/allegro/home/emacs/fi" load-path))
  (load "fi-site-init")

  ; It appears loading fi leaves emacs default directory hosed. Thus,
  ; let's set it back to the current directory ;;; Customize the common
  ; lisp invocation command for emacs.
  (setq default-directory (expand-file-name "."))
    
  ; The default buffer name is "*common-lisp*" but this can be changed
  (setq fi:common-lisp-buffer-name "*common-lisp*")
  
  ; The directory should be where emacs was started
  (setq fi:common-lisp-directory (expand-file-name "./"))

  ; The default buffer image name is "cl" but we use pb_clim2xm_composer
  (setq fi:common-lisp-image-name "class-lisp")
  
  ; The image arguments can be modified, new arguments can be added
  (setq fi:common-lisp-image-arguments nil)
  
  ; The host can also be specified
  ;(setq fi:common-lisp-host "faure")
    
  (defun acl ()
    "This function starts up Allegro Common Lisp with your defaults"
    (interactive)
    (fi:common-lisp fi:common-lisp-buffer-name
                    fi:common-lisp-directory
                    fi:common-lisp-image-name
                    fi:common-lisp-image-arguments)
    )

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
After modifying your .emacs file, you can start up Emacs and then type ESC-x acl which will open a window and start up ACL in that window. In case you cannot think of something to say, take lisp for a spin by typing the following:
   (sqrt 12321)
Lisp will come back telling you that the square root of 12,321 is 111. The tutorial below has more things to try.


Quick Tour of the Emacs to Lisp Interface

To get you started with the Emacs to Lisp interface, the following tutorial should be helpful. While you will be defining very simple Common Lisp functions in this tutorial, the point is not to explain the Lisp. Lisp as a language will be covered in the lectures with reference materials on reserve. The point is to get you a foot hold into the practical side of using Lisp from within Emacs. To begin, follow the instruction above for starting ACL within Emacs and get to the point where you are looking at the prompt:
     USER(1): 


Real Basic Stuff

You are now talking with the Lisp `read-eval-print' loop. What this means is that you type an expression into Lisp, it goes off and thinks about it - evaluating the expression - and then returns its answer. Thus, to evaluate the sum of the integers 1 and 2 enter:
     USER(22): (+ 1 2)
     3
The ( opens the expression, the symbol + indicates you wish to evaluate the following arguments with the function that performs addition, the arguments follow, and finally the expression is closed off with a right parenthesis ). The response, 3, is printed on the following line. So far pretty elementary... You can nest expressions in the following fashion.
     USER(23): (+ (+ 1 2) (+ 3 4))
     10
Many Lisp functions also allow variable numbers of arguments. Thus, you could accomplish the same addition with:
     USER(24): (+ 1 2 3 4)
     10
You can record values for later use by binding them to variables. Thus, you can introduce the symbol foo and bind it to the value returned from an expression.
     USER(25): (setf foo (+ 1 2 3 4))
     10
     USER(26): foo
     10
The first expression has bound the value 10 to the variable foo. The second expression, consisting only of the symbol name, when evaluated, returns the value of the symbol.


Making your own functions

You can add a function to the existing set of Common Lisp functions using the special form defun. For the moment, do not worry about what 'special form' means, we'll get there in lecture. Thus, to create a function to increment a value by 1, you type in the following:
     USER(27): (defun add-one (x)
	         "Adds one to its argument"
	         (+ x 1)
	         )
     ADD-ONE
You can now use this function just like any other function in the language.
     USER(29): (add-one 12)
     13
No introduction is complete without the "Hello World" program. So here it is:
     USER(30): (defun hello-world ()
	         "Repeat after me, hello world"
	         (format t "Hello World")
	         )
     HELLO-WORLD
     USER(31): (hello-world)
     Hello World
     NIL
With this example, we touch on a subtle point. A function can be instructed to print text using the format function. In this case, the text appears in the obvious place, the interaction window. What the function prints and what it returns as its value when evaluated should not be confused. The Hello World appearing when you evaluate the function is the consequence of executing the format statement. The NIL on the following line is the actual value returned by the function. NIL is a particularly important value. It has several interpretations which will only really make sense once you are more familiar with the basics of lisp. Think of it now as simply a null value.

Let's close out this section with a variant upon hello-world.

     USER(32): (defun hello-my-name-is (name)
                 "Program to greet newcomers other than Bob"
                 (if (string-equal name "Bob")
                     (format t "Go Away Bob")
                     (format t "Nice to meet you ~A" name))
                 )
     HELLO-MY-NAME-IS
     USER(33): (hello-my-name-is "Ross")
     Nice to meet you Ross
     NIL
     USER(34): (hello-my-name-is "Bob")
     Go Away Bob
     NIL


Help, I Typed The Wrong Thing, What Now?

You are a good typist if you have not already discovered the debugger. Here is an example:
     USER(53): (ehllo-world)
     Error: attempt to call `EHLLO-WORLD' which is an undefined function.
       [condition type: UNDEFINED-FUNCTION]

     Restart actions (select using :continue):
      0: Try calling EHLLO-WORLD again.
      1: Return a value instead of calling EHLLO-WORLD.
      2: Try calling a function other than EHLLO-WORLD.
      3: Setf the symbol-function of EHLLO-WORLD and call it again.
     [1] USER(54): 
The ACL debugger is a tremendously useful tool. However, our goal for the moment is simply to let you get back to `top-level' and forget about your typo. What you notice is that a [1] has appeared to the left of the usual prompt. Simplifying dreadfully, this means Lisp has caught your mistake, left a place holder as to what you were attempting to do, and is now again letting you evaluate expressions. The expressions can include directives to the debugger. The most basic directive means essentially 'get me out of here' and can be given by typing :pop. For example:
     [1] USER(54): :pop
     USER(55):    
You could alternatively type :help and Lisp would print out a complete listing of commands you can enter.


Keystrokes to Learn More

One of the great advantages of using Lisp from within the Emacs interface is the ability to call up the argument lists and function documentation on any function. This includes functions defined in the basic language as well as those defined by other people whose code you are using, and finally documentation on your own functions. (Alas, this interface seems to be unable to access the documentation strings for many of the basic Lisp functions.)

Getting Function Documentation

For example, imagine you know about the function hello-my-name-is, but you are not quite sure what it does. You can call up its documentation string by simply starting to type the function, i.e.
     USER(35): (hello-my-name-is   
Now, with the cursor placed to the right of the function name, type the following keystrokes:
     Esc-Sh-F   
To clarify our conventions for identifying keystrokes, this means you should depress the escape key, followed by the shift and F keys together. (Optionally, on some Sparc keyboards there is a key next to the space bar with a diamond on it. Anything that can be accomplished by typing escape followed by other keys can be done with the diamond depressing the diamond key while depressing the other keys.)

Emacs will now ask you in the small one line window at the bottom to confirm your request; it will say:

     Function documentation for symbol: (default hello-my-name-is)   
Typically you want the default, and so by simply entering Ret, Emacs will print the documentation string to either this same display line, if it is small, or to a help window if it is larger. So, in this case, you will see displayed:
     Program to greet newcomers other than Bob
This is your first way of finding descriptions of what functions in Lisp do.

One minor digression on the point of documentation strings, in a major step backwards, Allegro Common Lisp has adopted the convention of other Unix Common Lisp systems and saved disk and memory space by removing documentation strings from the common functions, which is too bad since systems 15 years ago running on Lisp Machines with 8MB of memory routinely kept complete documentation available with only a keystroke. When writing your own Lisp code, it is very good practice to include documentation strings.

Getting The Arguments to a Function

Another common frustration when writing code is not remembering the arguments to a function.

The function expt is used to raise a number to a power. This is a classic example of a function where one might forget the order of the arguments. Hence, you can type the following (leaving the cursor to the right of the last character)

     USER(51): (expt 
and now type
     Esc-Sh-a   
Emacs will ask you in the bottom window to confirm your request. Simply hit Ret and it will display the following:
     EXPT's arglist: (BASE POWER)   
This tells you the function takes two arguments. The first is the base and the second is the power to which you want it raised. Thus, to raise 8 to the 3rd power, you would type:
     USER(51): (expt 8 3)
     512
These are the two most basic and I find commonly used control keys for gaining information. There is one more mechanism which is independent of the Emacs to Lisp interface but still incredibly useful, and that is the apropos function

Apropos: Give Me Things with Names Containing a String

You remember there is some function you want to use, but you cannot remember the exact name. However, you are pretty sure it contains the string "hello". Do the following:
     USER(52): (apropos 'hello 'user)
     HELLO-MY-NAME-IS    [function] (NAME)
     HELLO
     HELLO-WORLD         [function] ()
The function apropos looks for all things defined which contain the indicated string in their names. The way you restrict attention to those things in the user package is with the second argument. I recommend doing this until you understand more about packages: otherwise you'll see many things which will make little sense to you.

Note that you are told what things it finds, along with whether they are functions, and if so what arguments they take.


I Want to Write My Programs In Files

While using the Lisp interaction buffer of Emacs to write simple expressions is fine; however, whenever you are starting to write a real program, you will want to do so in a named file which you keep around. There are some nice features of the Emacs to Lisp interface to help you.

Let's begin by creating a file. You can do this easily in Emacs using the keystrokes C-x C-f. Again, this is shorthand for typing control x followed by control f. Emacs will now ask you to enter the name of the file at the bottom of the screen. For this tutorial you should type:

     my-name-is.lisp   
Be aware that Emacs may already give you a path to which what you type is appended. If the path is to the directory where you want to put the file (which it should be by default), this is helpful. However, if you don't watch and it tries to create the file in some other directory, this can lead to problems.

If a file of this name already exists, you will now be in a new buffer looking at the contents. More likely, no such file existed beforehand, and you are now looking at a new buffer which is empty.

For this tutorial, your file my-name-is.lisp should contain the following:

     ;;; File containing a simple function example
     (in-package user)
     
     (defun my-name-is (name)
       "Program to greet any  newcomers other than the Bob"
       (if (string-equal name "Bob")
           (format t "Go Away Bob")
           (format t "Nice to meet you ~A" name)
           )
       )
A copy of this file can be found at my-name-is.lisp.

Now you are ready to learn something about how to communicate between files containing your Lisp code and the Common Lisp buffer.

Evaluating a Previously Entered Expression

In the *common-lisp* buffer you may want to make a minor change to a previous line you entered and then evaluate it again. This is made extremely simple for you by the emacs to lisp interface. If you simply put the cursor at the end of any expression in the buffer and hit return, emacs will submit this expression to the Lisp interpreter. You can also use emacs to make changes in the line before you hit return.

Evaluating/Compiling an Emacs Buffer

Go to the buffer containing your file. Type the following:
     C-c C-b   
You will see it display the message that it is compiling. If you have entered everything correctly, it will quickly follow the compiling message with the word done at the bottom of the screen.

Now you can go to the Common Lisp buffer and do the following:

     USER(61): (my-name-is "Ross")
     Nice to meet you Ross
     NIL
     USER(62): (my-name-is "Bob")
     Go Away Bob
     NIL
     USER(63): 
Your function has become part of the Lisp environment and can be used like other functions.

Evaluating/Compiling Part of a Buffer

If you go back to the file my-name-is you can compile just the function definition by placing the cursor at the end of the defun expression. This is after the final ) which closes off the function at the bottom of the file. Now simply type:
     C-c C-s   
Try this by changing Bob to your own name and running the function. In my case, I modify the function so it appears as follows:
     (defun my-name-is (name)
       "Program to greet any  newcomers other than the Ross"
       (if (string-equal name "Ross")
           (format t "Go Away Ross")
           (format t "Nice to meet you ~A" name)
           )
       )
Then I place the cursor at the end of the function and type C-c C-s. The compiling message followed by the done message appears at the bottom of the screen. Now if I call the function in the Common Lisp buffer I get the following response:
     USER(64): (my-name-is "Ross")
     Go Away Ross
     NIL
     USER(65): 

Automatically Loading Files Where Functions Reside

A more advanced, but very convenient feature of this interface is that with one keystroke you can load the file in which a function is defined. If you are just getting started, and feel you have learned enough, you need not push on through this section. To really see the benefit of this, you will want first to delete the buffer in which you have the file in which you have defined the function my-name-is. A reminder about Emacs, to do this, you can simply type:
     C-x k   
If you are already in the buffer containing your file, this will be the default and you need only hit return. Now, if you type:
     C-x C-b   
Emacs will display a complete list of all the buffers as well as what files are associated with those buffers which represent files. Note some buffers, like the *common-lisp* buffer have no corresponding files.

A passing comment, one way to move between buffers is to move the cursor into this display, select a line naming a particular buffer and type f. This will bring up this buffer in the window.

Now, to see how Emacs can track down where you source code lives, go to the Common Lisp buffer and type out the name of the function

     USER(66): (my-name-is 
and without completing it and leaving the cursor at the right most point on the line, type
     C-c .   
Emacs will ask you the following question at the bottom of the screen:
     Lisp Locate source: (default my-name-is)   
If you type return, then Emacs will find the source file in which this function is defined, load it, and open it up in a window. Initially, you may not find this capability important, but as you begin to manage larger programs, it can be very handy.



Written by Ross Beveridge and Adele Howe
Last updated on 2/26/97

Comments: howe@CS.ColoState.EDU ; ross@CS.ColoState.EDU
Copyright © 1998: Colorado State University, CS Department. All rights reserved.