CSE 341 -- Programming Languages

Autumn 2003

Department of Computer Science and Engineering, University of Washington

Steve Tanimoto (instructor)

Assignment 2

Version 1.0 of October 2

Lisp Warmup 

Due date and time: Part I: Friday, October 10, 2003 (12:30 -- beginning of class); Part II: Monday, October 13, 2003 (midnight).

Turn in this assignment in two parts: Part I as a hardcopy printout, and Part II using web-based turn-in.


 

Title: Introduction to Lisp.

Purposes: Learn to use Lisp syntax, built-in functions, how to define recursive functions, understand Lisp evaluation, and how to manipulate list structures.

Instructions: Read pages 2-73 in Symbols, Programs, Interaction. (You may purchase a copy at Rams Copy at 4144 University Way, N.E.

Part I

Do the following exercises:

Part II

In this part of the assignment, you will define a series of functions of increasing complexity, culminating in a facility that translates mathematical expressions from Lisp's own syntax to that of the mathematical typesetting language LaTeX.
 
There are four "steps" to this part of the assignment, each one taking you closer to the goal. This is a relatively long assignment, but much of the text on this page is tutorial in nature. Also, we have set a later turn-in deadline for this part than was originally given.
 
Step 1. Defining recursive functions. In list processing, to transpose means to interchange two elements of a list.
 
Write a function TRANSPOSE in Lisp that will take two arguments: a list and an integer, and will return a new version of the list in which a certain transposition has been performed. For example:
 
(transpose '(a b c d e) 2)  =>  (A B D C E)

 
Here, the 2 indicates that the tranposition involves the elements in position 2 (third element, since indexing starts at 0 in Lisp) and position 3. Next, make a variant of this function that does lots of transpositions. It should take a list and transpose the first and second elements, third and fourth elements, etc., returning the resulting list. If there is an odd number of elements, the last one is not moved. Here's an example:
(transpose-all '(a b c d e))  => (B A D C E)
Here there is an odd element, E, at the end that doesn't move. With an even number of elements, they would all trade places with a neighbor.
 
After that, create a doubly-recursive version of it called DEEP-TRANSPOSE-ALL that works on any and all sublists (at all levels) as well as the top-level elements. Here's an example. Note that a sublist serves as an element at the level of the expression it occurs in, and so it will trade places with another element (unless it is an "odd man out" like the element E in the previous example).
(deep-transpose-all '(a b (c d (e f) g) h)) =>
  (B A H (D C G (F E)))

 
Step 2. Now that we've got double recursion under our belts, let's apply it to the problem of converting ordinary Lisp syntax into something that looks (slightly) more like conventional mathematics. Here is a definition for a function called PREFIX-TO-INFIX and its helper, INFIX-SERIES. Your job is to create deep versions of them so that subexpressions will be handled, too. PREFIX-TO-INFIX takes a single argument, which is a Lisp expression involving +, *, -, or /, and any numbers or symbols that represent arguments to those operations. INFIX-SERIES takes two arguments: an operator like + or * and a list of arguments. Its job is to form a list in which there is a separate copy of the operator in front of each argument. It returns the new list. The deep versions must correctly handle sublists at any depth within the main expression. The examples here show how these functions should work.
(defun prefix-to-infix (exp)
  (if (member (first exp) '(+ *))
    (cons (second exp)(infix-series (first exp)(rest (rest exp))))
    exp) )

(defun infix-series (op args)
  (if (null args) nil
    (cons op (cons (first args)(infix-series op (rest args)))) ) )

;;; (prefix-to-infix '(+ 1 2 3 4))  => (1 + 2 + 3 + 4)

;;; (deep-prefix-to-infix '(+ 1 2 (* 3 4 5))) =>
;;;    (1 + 2 + (3 * 4 * 5))

 
Step 3: Working with strings. (See appendix explaining the importance of strings.) Two of Common Lisp's most important string processing functions are FORMAT and CONCATENATE. Each has its own idiosyncrasies. FORMAT is typically used to format and print information, but it can also be used to prepare strings in special ways, and it can even be used to concatenate two given strings. CONCATENATE can be used to build longer sequences (including strings) from shorter ones, and it is not limited to two arguments.
 
Here is a simple example of using FORMAT to prepare a string that includes the value of a Lisp arithmetic expression.
(format nil "Here is PI divided by 2: ~A. That's it." (/ pi 2))
;;; =>  "Here is PI divided by 2: 1.5707963267948966. That's it."
The first argument to FORMAT here indicates what output stream to use. NIL has a special significance here, telling FORMAT not to use any output stream. FORMAT returns the string as its value rather than printing it or writing it to, say, a file.
 
Here is an example of how we can use CONCATENATE to combine three strings
;;; (concatenate 'string "abc" "d" "efg")  => "abcdefg"
Because this looks a little awkward, having to always give the second argument STRING to tell CONCATENATE to produce a string, as opposed to a LIST, let's use our own simpler function CAT, defined as follows:
(defun cat (&rest args)
  (apply #'concatenate 'string args) )
We can use it as follows:
;;; (cat "abc" "d" "efg")  => "abcdefg"
Now let's apply strings with single recursion to do a simple kind of translation of a list into another expression. Here is a sample function that takes a list representing a set of objects and returns a string representing that set in a more traditional mathematical notation.
(defun lisp-to-set (lst)
  (if (null lst)
     "{}"
     (cat (format nil "{~A" (first lst))
          (lisp-to-set-help (rest lst)) ) ) )

(defun lisp-to-set-help (lst)
  (if (null lst) "}"
    (cat (format nil ",~A" (first lst))
         (lisp-to-set-help (rest lst)) ) ) )

;;; (lisp-to-set '(a b c)) => "{A,B,C}"
Your job in this step is to write a function LISP-TO-[LIST] that takes a list as an argument and returns a string in which each left parenthesis is represented by "[" and each right parenthesis by "]".
;;; (lisp-to-[list] '(this is a (((deep))) test)) =>
;;;   "[THIS IS A [[[DEEP]]] TEST]"

 
Step 4. Translating into another language.
 
Now we've licked the main ingredients for translation of nested expressions: doubly-recursive processing and conversion of lists to strings. Let's apply these techniques to a real-world task: translation of Lisp expressions (limited to certain arithmetic operations) into LaTeX source.
 
About LaTeX: You don't need to know much about LaTeX to do this. However, LaTeX ("Lamport's TeX") is a formatting system built on Donald Knuth's TeX system that is used by lots of computer scientists and mathematicians to format their technical papers.
 
A LaTeX source file consists mainly of ordinary text plus formatting commands. However, there are special facilities for specifying the formatting of mathematical expressions. Here is an example of a sentence that includes two mathematical expressions, in LaTeX.
 
"Let the variable $y$ represent the value of $2 x^3 + x^2 + 3x - 1$."
 
The first mathematical expression is $y$, and the formatting causes the y to be typeset in an italic font. The second formula is $2 x^3 + x^2 + 3x - 1$. In this formula, the numbers before the x's (the coefficients) get typeset in a normal font, the operators + and - get typeset with mathematical symbols, and the exponents are raised and typeset in a smaller font. If we wanted a multi-character exponent, we would put it within curly brackets: for example, $x^{n+1}$. The dollar signs are used to start and end "math mode."
 
There are many interesting formatting capabilities in LaTeX, but let's just consider three more: square root, fractions with bars, and special symbols. The LaTeX source for the law of Pythagoras is $c = \sqrt{a^2 + b^2}$. Here we see that the square-root sign is obtained by using the command \sqrt, and the argument to it is given within curly brackets.
 
To get a fraction with a horizontal fraction bar, we use an expression like this:
$r = \frac{c}{2 \pi}$.
This expression can be interpreted as "radius equals circumference divided by two times pi." Here the \frac command requires two arguments, each one surrounded by curly brackets. Note that \pi is a command that causes the Greek letter pi to be printed.
 
Here are some commands that produce special symbols or names in LaTeX:
LaTeX       Lisp
-----       ----
\log        LOG
\sin        SIN
\cos        COS
\pm         +-  (the "plus or minus" sign used
                 in the quadratic formula
                 and in expressing error intervals
                 in the sciences and engineering.
                 Note: this is not standard in Lisp)
\pi         PI
\,              (No real counterpart in Lisp -- " "?
                 In LaTeX it means put in some additional
                 white space, the width of the character ",").

 
Within LaTeX's math mode, extra spaces between symbols do not affect the output.
 
What to write: Write a main function named LISP-TO-LATEX that takes a single argument (an arithmetic expression in Lisp) and that returns a single value (a string). You should handle any valid Lisp expression made up of numbers, single-letter symbols (that we assume represent variables) and the following functions: +, -, *, /, SIN, COS, LOG, EXPT, SQRT, +- (which is not standard but we'll use to represent the "plus-or-minus" operator). The string that is returned should represent a mathematically equivalent formula, in LaTeX format. It should not contain the enclosing dollar signs that change into and out of math mode. The formula should all be on one line (no embedded newline characters. The expression may contain subexpressions, and those should all be translated correctly. You may assume that / is used as a binary operator, even though Lisp permits it to take fewer or more than two arguments. With + and *, you may assume they always take 2 or more arguments in the input expression. With -, assume it takes either one argument (unary minus) or two arguments (representing simple subtraction). Also, write any helping functions that you need. Comment every function you write either with regular comments preceded by semicolons or by giving a documentation string within each function.
 
Testing your output: To test your output, place it in a file that looks like this:
\documentclass{article}
\begin{document}
Here is my formula, in display-math mode:

$$c = \sqrt{a^2 + b^2}$$

\end{document}

 
The formula in this example has double dollar signs around it, which specify "display-math" mode. The formula is then typeset on a line all by itself, nicely centered.
 
After you have a file with these contents (where the formula is what your program produces), and assuming you have named your file "myfile.tex", you can typeset it on a Unix system with the commands
 
latex myfile.tex
dvips -o myfile.ps myfile.dvi

 
Then you can print out the file myfile.ps on a Postscript printer. You can also view it directly if you have Ghostview installed, or you can convert it to PDF with Adobe Acrobat (I just double-click on myfile.ps, since I have Acrobat installed.)
 
Test your translation function on the Lisp expression for the quadratic formula:
(/ (+- (- b) (sqrt (- (expt b 2)(* 4 a c)))) (* 2 a)) 
The corresponding output should look like:
"\\frac{{-B\\pm\\sqrt{B^2-4AC}}}{2A}"
Here, the backslash characters are doubled, because in Common Lisp, the backslash character is the normal escape character, and so to get an actual backslash character into a string, it has to be preceded by another backslash. To show the string without the extra backslashes and without the surrounding double quotes, we can print the string with PRINC, resulting in:
\frac{{-B\pm\sqrt{B^2-4AC}}}{2A}
However, your LISP-TO-LATEX function should return the string itself. It should NOT try to remove any of these "extra" backslashes.
 
Automatic Testing: We are planning to use an automatic testing procedure to help grade your assignment. We'll ask you to submit a file called a2.lsp that contains all of your function definitions for Part II. Submission will be via a Turn-in procedure to be described later. We plan to test your LISP-TO-LATEX function by calling it with a couple of different formulas and then using our own functions and scripts to translate your output string into a LaTeX source file and process it.

Additional Information

Some additional information relevant to this assignment is posted in an appendix.

Scoring

Scoring for this assignment: 25 points for Part I and 50 points for Part II. Total: 75 points.