Getting Started with ACL2 Programming in ACL2s

We assume that you have read A Gentle Introduction to ACL2 Programming.

You might also want to refer to the Hyper-Card for ACL2 Programming in ACL2s.

Learn to Use the Documentation

Goal: Find out about the function AND

Goal: Using the analogous method, find out about the function REVAPPEND.

Running ACL2

You should always use ACL2 in conjunction with a text editor or a graphical development environment. For these exercises we will use ACL2s, an Eclipse-based integrated development environment (IDE) for ACL2.

Obtain and install ACL2s from the ACL2s home page. Read the beginning tutorial and the guide to usage.

Once you have Eclipse running with ACL2s, do the following (see the ACL2s beginning tutorial for details):

The last two commands turn off ACL2's theorem prover and allow you to use ACL2 as a Lisp execution engine.

The ACL2 Prompt

Pay special attention to the prompt!

It should be

ACL2 p!>
If it is not, something is wrong! Have you followed the directions above?

Note that the ``ACL2'' you see is not a sign that you are in the ACL2 system. It is a sign that the ``current symbol package'' is ACL2. If you do not know what a symbol package is, don't worry about it. Just know that it is not the ``ACL2'' that is important about the prompt, it is the other parts!

Evaluating ACL2 Expressions

If you type an ACL2 expression at the prompt, followed by a return, ACL2 will read the expression, evaluate it, and print the result. Try typing after the ACL2 prompt in the session editor. Then type return. It should print T. The value of the Lisp expression t is T.

Try these three:

The first should return NIL because 1 is not 2. The second and third should return 1 and 2, respectively, because (if x y z) means ``if x then y, else z.''

One advantage of using ACL2s is that it will catch syntax errors that would throw you into the debugger if you were interacting with ACL2 directly. Try typing the following, including the period at the end of the line, and then type return:

ACL2 will process the expression (equal 1 1) and leave the . at the prompt. If you type return again, ACL2s will produce an "Illegal dot" error message.

More Evaluation

Rather than type expressions directly at the prompt, you can enter them in the code editor (test.lisp) and then click the "Advance todo line" button on the toolbar to send the expressions to ACL2. See the ACL2s documentation for details.

Here are some expressions to evaluate. But before you send each one to ACL2, think about what you believe the value will be. When you have a hypothesis, evalute the expression and see if you're right.

Remember AND? Evaluate these expressions. What happens if you call a function with the wrong number of arguments? What happens if you try to evaluate an expression that contains a variable? The error message is not very helpful to the new user. It ought to say: ``ACL2 cannot evaluate top-level expressions that contain variables!''

Which of these expressions evaluates to (1 . 2)?

Warning: If you evaluated the last expression, ACL2s will produce an error message! The object 1.2 is a Common Lisp floating point number and ACL2 doesn't support those.

More generally, if you want to write a dotted pair, you should put some ``whitespace'' before and after the dot! Write '(A . B) not (A.B).

Which of these expressions evaluates to (1 2 3)?

Which of these expressions evaluates to (A B)? Which of these expressions evaluates to (A (B . C) D)? What is the value of the following? Recall or review the documentation first.

Learning to Define Functions

Now let's define the list membership function.

You could just type the following at the ACL2 prompt. But don't!

(defun mem (e x)
  (if (consp x)
      (if (equal e (car list))
          t
          (mem e (cdr x))
      nil)))
It is almost always a mistake to type more than one line directly to Lisp! The reason is that Lisp will not let you edit your input after you have typed a carriage return (it provides a one line buffer). And there are typos in the defun above!

Type the definition in the code editor and then press the "Advance todo line" button to send it to ACL2. This will cause an error. The trouble is that the parentheses are not balanced correctly in the definition. The error message says IF was given four arguments and expects three. Can you find the problem? Hint: use ACL2s' parenthesis-highlighting capability.

Edit the defun to fix the problem. When you have fixed the paren problem, resubmit the definition to ACL2.

Now what? The error message:

ACL2 Error in ( DEFUN MEM ...):  The body of MEM contains a free occurrence
of the variable symbol LIST.
means that the defun uses a variable that is not one of the formal parameters. ACL2 does not have global variables! The variable list in the defun should be x. Fix it and try again.

Whenever we say something like ``define such-and-such'' in ACL2 we really mean for you to prepare the definition in the code editor, so you can correct your typos, and then submit it ACL2 as described above. If you always type new definitions at the bottom of the code editor, and submit them as you go, you will have a record of your definitions in the .lisp file and the associated ACL2 history in the .lisp.a2s file.

Ok, so you've defined mem. Test it on

Factorial

Now put this definition into your code editor:
(defun fact (n)
  (if (equal n 0)
      0
      (* n (fact (- n 1)))))

Once you have done that, submit it to ACL2. Now run it:

What's wrong? Fix it and resubmit it. (fact 4) ought to be 24. You will be re-defining a function, which ACL2 takes somewhat seriously. You should answer y when it asks you if you want to redefine FACT. ACL2 may cause an error on the last example, depending on the Common Lisp image you are using! It is a fairly safe bet that there is a value of n for which your image cannot compute (fact n) and will exhibit a ``hard error'' like this:
Error: Invocation history stack overflow.
Fast links are on: do (si::use-fast-links nil) for debugging
Error signalled by IF.
If you were interacting with ACL2 directly, you would see the Lisp debugger prompt. However, because you are using ACL2s, you will see the error message but still be able to proceed normally.

The stack overflowed because fact is being interpretted. Compiled functions use less stack space. To compile fact, do

Then try Is that the answer you expected? Note: In some Common Lisps, even the compiled version of fact may cause a hard error and, again, if yours computes (fact 1000) it still may not compute (fact 10000), etc.

A Challenge

Now its time for you to think.

Suppose we have a cons pair, e.g., (1 . 2) and we want to flip it around so that we have (2 . 1). Fill in the blank below so that the function flip does this. (You should move the defun to the code editor and prepare your definition there.)

(defun flip (p) 
  ...)
It doesn't matter what flip does if p is not a cons pair, because you should never call flip on such a p.

Test your flip

(Some people are surprised at how the last answer prints out. Think about it.)

Now suppose we have a list of cons pairs, x, and we want to flip each element of x. Fill in the blank to make flip-list do that.

(defun flip-list (x)
  ...)

Test your flip-list

The answer should be ((1 . A) (2 . B) (3 . C)).

Follow-Up Exercises

Here are some other exercises you might want to do to learn ACL2. They are exhibited as function definitions for you to complete. After each one is an example that tests the equality of your answer with the expected answer. All the examples should evaluate to T. The End