Professional Documents
Culture Documents
chp2 Forms
chp2 Forms
2.1 Form
2.2 Evaluation
2.3 Data
2.4 List Operations
2.5 Truth
2.6 Functions
2.7 Recursion
2.8 Reading Lisp
2.9 Input And Output
2.10 Variables
2.11 Assignment
2.12 Functional Programming
2.13 Iteration
2.14 Functions As Objects
2.15 Types
2.16 Looking Forward
Notes
2.1 Form
> clisp
[1]> 1
1
[2]> ( + 2 3)
5
[3]> (+)
0
2.2 Evaluation
First, arguments are evaluated left to right.
The values are passed to the operator.
therefore to evaluate
(/ ( - 7 1) ( - 4 2))
If Lisp can't understand what you typed, it will display an error message and put
you into a version of the toplevel called a 'break loop' .
The break loop gives an experienced developer a chance to figure out what is wrong,
but in the beginning you just want to get out and back to the toplevel. What you
have to do to get back depends on the implementation
SBCL
* (/ 1 0)
(SB-KERNEL::INTEGER-/-INTEGER 1 0)
0] 0
clisp
[4]> (/ 1 0)
The quote operator is a special operator that does **not** follow the above
evaluation rule.
Instead of evaluating arguments, it just returns its argument as is
Lisp gives you a way to prevent evaluation of expressions. The next section
explains how this is useful.
2.3 Data
Lisp provides datatypes other languages do, along with a few others don't.
Examples of the former are integers and strings. Examples of the latter are symbols
and (literal?) lists.
Example of symbols - they are converted to ALL CAPS
[8]> 'artichoke
ARTICHOKE
the first argument is quoted so yields itself. The second argument is not quoted so
is treated as (and evaluated as ) a function call.
In CL there are two ways of representing the empty list. () and nil (_ note : nil
is *equivalent to an empty list. note 2: Not '() necessarily, 'though it can't
hurt' )
cons is a list builder function. It returns a list with the (evaluated result of)
the first argument added to the front of the second argument, which must be a list.
the list function we saw before is just a convenient way to cons several things
onto an empty list.
2.5 Truth
[14]> t
T
nil (the symbol) plays the role of both *false* and *the empty list*.
so functions that expect or return one work with both
e.g:
[22]> (> 2 3)
NIL
similarly the function null (_ note: not nullp!!) returns true for both the empty
list and nil and false)
Simplest conditional in CL
e.g:
> (if ( listp ' ( a b c))
(+ 1 2)
(+ 5 6))
3
[38]> (if 0 1 2)
1
> (and 0 3)
3 (_ !! == (and t 3) == 3)
[40]> (or 0 3)
0
(if the and operator finds an argument that evaluates to false, it stops. The or
operator stops when it finds an argument that evaluates to true)
Both or and are macros (see chapter 10) Like special operators (if, and ...) macros
can circumvent the evaluation rule.
2.6 Functions
New functions are defined with defun. It takes 3 or more arguments. A function
name, a list of parameters, and a body for the function.
e.g:
(defun our-third (x)
(car (cdr (cdr x))))
2.7 Recursion
Functions can call other functions to get work done. Recursion = functions calling
*themselves* to get work done.
eql is a predicate that tests whether its two arguments are identical.
e.g;
Note:
1. t as first argument say 'send output to 'the usual place' '
2. the second argument is the string template. Within the template each ~A
denotes a position to be filled (by a value's text representation)' and ~% denotes
a new line. The positions (indicated by ~A) are filled by the (text representation
of) the following values.
Note that there are *two* things printed to the output. The first line is displayed
by format. The second line is the value *returned* by format, displayed as usual in
the top level. Ordinarily a function like format is not used from the toplevel, but
from within a program, so the returned value (here, nil) is never seen.
a function that asks the user a question, reads input, and whatever is entered
keep in mind: read will wait till you type in something. So it is usually unwise to
use read without an explicit prompt.
(KEY) read is a complete lisp parser, it doesn't return a string, it parses what it
reads and returns the lisp object that results.
The body of askem shows something we haven't seen before. The function body
contains more than one expression.
a function body can contain any number of expressions. When the function is called,
they are evaluated in order, and the return value of the last expression is
returned.
2.10 variables
A let expression has two parts - the first is a list of instructions for creating
variables, of the form (variable-name, expression).
These variables are valid within the body (see below) of let.
The second part is a body of expressions, evaluated in order, with the value of the
last being returned.
(defun askem ()
(format t "please enter a number. ")
(let ((val (read)))
(if (numberp val)
val
(askem))))
[7]> (askem)
please enter a number.e
please enter a number. f
please enter a number. g
please enter a number. 23
23
[8]>
The function creates a variable val, with let, to hold the value returned by
(read). the function. then looks at this value to decide whether it wants to return
it. numberp is a predicate that checks if a value is a number.
Variables like the ones we used are called local variables. They are only valid
within a certain context.
also note that while defconstant doesn't need a quoted symbol, boundp does.
2.11 Assignment
In Common Lisp,the general assignment operator is setf, which can be used to assign
to both global and local variables.
thus
The first argument can be any expression that refers to a particular place. Such
operators are "settable".
You can give even numbers of arguments to setf to assign many variables at once.
e.g
(setf
a 3
b 2
c 4)
this is equal to
(setf a 3)
(setf b 2)
(setf c 3)
E.g: The function remove takes an object and a list and returns a *new* list
containing everything in the list argument but that object.
[24]> x
(N B C)
[25]> (remove 'n x)
(B C)
[26]> x
(N B C) ;; x is unchanged. remove has no side effects.
[27]>
FP allows interactive testing. (_ the return value depends only on the input
parameters so) if the function returns correct values for input values, you can be
sure it is correct. You can get 'instant turnaround' when you make changes anywhere
in your program. This enables a whole new style of programming.
2.13 Iteration
the remaining arguments comprise the body of the loop. They will be evaluated
in order, on each iteration.
on each iteration, (1) the variables are updated. (2) the termination test is
evaluated, and if it fails (3) the body is evaluated.
[8]> (defun show-square (start end)
(do
( (i start (+ i 1)) ) ; list of variable specifications
( (> i end) 'done) ; first element is iteration-done-check, second is
what to return when iteration done
(format t "~A ~A ~%" i (* i i)))) body of expressions, evaluated in order
(here only 1 expression - the format one)
SHOW-SQUARE
[11]> (show-square 2 7)
2 4
3 9
4 16
5 25
6 36
7 49
DONE
progn takes any number of operators, executes them in order, returns the value of
the last (_ it is the basic sequencing operator).
functions are regular objects like symbols, strings, or lists. (_ iow a function is
'just another value'.)
if you pass a function name to the 'function' operator, it will return the
associated (_underlying function) object.
Like quote, function is a special operator so you don't have to quote the argument
[4]> (function +)
#<SYSTEM-FUNCTION +>
Like quote, function has an abbreviation #'. This is called "sharp quote".
[5]> #'+
#<SYSTEM-FUNCTION +>
note: so far we dealt with objects that look the same when CL displays them as when
we type them in.
Functions are different, and could be a segment of machine language code.
(_ this seems to be case where the second position in a list is *not* a 'function
position', so if we want to put a function there we have to use #'fn-name, and not
just fn-name as in scheme)
it (apply? or apply #'+) can be given any number of arguments, as long as the last
argument is a list.
The function funcall does the same but does not need the arguments in a list
lambda
We use the defun macro to create functions and give them names.
But functions don't (_ always) need names, and we don't need defun to define them.
Like other kinds of lisp objects ('datatypes') we can refer to functions literally
(_ we can have function literals like we have integer literals)
a function that adds two numbers can be defined and applied with
(_ note: we need the sharp quote because th 2nd position in a list is not 'function
position', so we can't just pass in the lambda literal directly, we have to extract
the function from the function name space)
What is lambda?
((x) (+ x 2))
instead of
but lisp programmers were used to beginning functions with lambda, so the tradition
was retained in CL.
2.15 Types
(_ that said) though type declarations (_ on variables) aren't required, you can
make them for reasons of efficiency (see chapter 9 for numeric types)
The function typep takes a value and a type specifier, and returns true if the
value is of that type.
[15]> (typep 23 T)
T
In this chapter we have barely scratched the surface of lisp. Still a portrait of a
very unusual language is emerging.
- to start with, the language has a single structure ( a list, which is a CL
datastructure) to express all program structure.
e.g functions are expressed as lists
- lisp itself is a collection of functions (_ and special forms, macros)
don't worry if connections between all the features of lisp aren't obvious yet. It
takes time to get used to all the things you can do with it.
you can not only write your program in lisp, but you can also improve the language
to suit your program. To understand the essence of lisp, this idea is a good
starting point.
Summary:
1. Lisp is an interactive language, If you type an expression into the
toplevel, lisp will display its value.
3. The evaluation rule for Common Lisp is : evaluate arguments from left to
right, and pass them to the function denoted by the operator. The quote (special)
operator has its own evaluation rule, which is to return the argument unchanged.
4. Along with the usual value, lisp has symbols and lists. Since lisp programs
are expressed as lists, it is easy to write programs that write programs.
5. The three basic list functions are cons, which builds a list. car which
returns the first element of a list, and cdr which returns everything in a list
after the first element.
7. Lisp consists (_ mostly) of functions. You can define new ones with defun.
10. The basic i/o functions are read, which is a complete lisp parser, and
format, which generates output based on templates.
11. you can create new local variables with let and global variables with
defparameter.
12. The assignment operator is setf. It's first argument can be an expression
(_ denoting a 'place')
13. Functional Programming, which means avoiding side effects is the dominant
paradigm in lisp. (_ but, no tail recursion,so not as efficient as imperative code)
15. Functions are regular lisp objects-they can be passed as arguments, and
denoted by lambda expressions.
Exercises:
(a) (+ (- 5 1) (+ 4 7))
answer. 15
verify
[1]> (+ (- 5 1) (+ 4 7))
15
(b) (list 1 (+ 2 3)
answer: ( 1 5)
verify:
[2]> (list 1 (+ 2 3))
(1 5)
3. Using car and cdr write a function that returns the fourth element of a list
4. define a function that takes two arguments and returns the greater of the two
(defun our-max (x y)
(if (> x y)
x
y))
[12]> (our-max 2 3)
3
[13]> (our-max 2 2)
2
[14]> (our-max 3 2)
3
from https://z0ltan.wordpress.com/2016/12/15/solutions-to-chapter-1-exercises-ansi-
common-lisp-2nd-edition/
enigma checks if a non null lisp contains at least one nil element
5(b)
(defun mystery (x y)
(if (null y)
nil
(if (eql (car y) x)
0
(let ( (z (mystery x (cdr y))))
(and z (+ z 1))))))
; poking and prodding
[26]> (mystery 2 '( 3 4 5))
NIL
[27]> (mystery 2 '( 2 4 5))
0
[28]> (mystery 2 '( 4 2 5))
1
[29]> (mystery 2 '( 4 3 2))
2
[30]> (mystery 2 '( 4 3 0))
NIL
x is an object, y is a list
if y is an empty list return nil
if the first element is equal to x return 0
else let z be the result of (mystery x cdr x)
if z is not null, return + 1 to z
Problem 6:
verify:
(b) (x 13 (/ 1 0))
13
funcall is the wrong answer. apply is the correct answer (Nil also works as empty
list)
but
Problem 7:
Using only the operators introduced in this chapter, define a function that
takes a list and returns true if one of its elements is a list
Problem 8:
Give recursive and iterative functions that
(a) takes a positive integer and prints that many dots
(b) takes a list and returns the number of times the symbol a occurs in it
8(a) recursive
a function that takes a positive integer and prints that many dots. recursive.
(defun print-n-dots(n)
(if (eq n 0)
(format t "~%")
(progn
(format t ".")
(print-n-dots (- n 1)))))
8(a) iterative
a function that takes a positive integer and prints that many dots. iterative
(defun print-n-dots-iterative (n)
(do ( (cntr n (- cntr 1)) )
( (eq cntr 0) (format t "~%"))
(format t ".")))
8(b) recursive
a function that takes a positive integer and returns how many times the symbol a
occurs in it
(defun count-a (lst)
(if (null lst)
0
(if (eq (car lst) 'a)
(+ 1 (count-a (cdr lst)))
(count-a (cdr lst)))))
8(b) iterative
(defun count-a (lst)
(let ( (cnt 0) )
(dolist (obj lst)
(if (eql obj 'a)
(setf cnt (+ 1 cnt))))
cnt))
Problem 9:
A friend is trying to write a function that returns the sum of non-nil
occurrences in a list. He has written two versions of this function, and neither
works. Explain what is wrong, and fix.
9 (1)
;friends version 1
(defun summit(lst)
(remove nil lst)
(apply #' lst))
problem: remove is functional it creates a new list with the non nil elements of
the passed in list. Also only the last expressions value is returned.
fix
9(2)
friends version 2
problems:
1. the first problem is that (car nil) does not throw an error in CL.
[48]> (car nil)
NIL
so the above function would never terminate. The base case is when the list
itself is nil.
fix: