You are on page 1of 20

Chapter 2: Welcome to Lisp

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

In (+ 2 3) + is the 'operator' and 2 and 3 are the 'arguments'.


+ can take any number of arguments including 0

[3]> (+)
0

All lisp expressions are atoms (e.g 1 ) or lists

2.2 Evaluation
First, arguments are evaluated left to right.
The values are passed to the operator.

therefore to evaluate

(/ ( - 7 1) ( - 4 2))

left most *argument* is (- 7 1 ) this is evaluated first


within this expression 7 is leftmost argument. It is evaluated (to itself),
resulting in 7
1 is the next left most expression, it also evaluates to itself, resulting in 1
these evaluation results (here the numbers 7 and 1) are passed to the -
operator resulting in 6
the next leftmost argument is (- 4 2)
within this , leftmost argument is 4, which evaluates to itself
the next argument is 2, which also evaluates to itself
these results (here 4 and 2) are passed to the - operator, resulting in 2
the evaluated arguments (here 6 and 2) are passed to the / operator, resulting in
3

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)

debugger invoked on a DIVISION-BY-ZERO in thread


#<THREAD "main thread" RUNNING {100399C4B3}>:
arithmetic error DIVISION-BY-ZERO signalled
Operation was /, operands (1 0).

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):


0: [ABORT] Exit debugger, returning to top level.

(SB-KERNEL::INTEGER-/-INTEGER 1 0)
0] 0

clisp

[4]> (/ 1 0)

*** - /: division by zero


The following restarts are available:
ABORT :R1 Abort main loop
Break 1 [5]> :R1

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

[6]> (quote (+ 3 5))


(+ 3 5)

' is an abbreviation so '(+ 3 5) is the same as (quote (+ 3 5))


[7]> '(+ 3 5)
(+ 3 5)

It is more common to use ' than (quote ...)

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

Note: symbols don't (usually) evaluate to themselves. So to refer to a symbol, use


quote.

Lists are represented as elements enclosed in parenthenes. The elements can be of


any type including lists.
Lists need to be quoted else Lisp will evaluate them as function applications.

[1]> '(my 3 "sons")


(MY 3 "sons")

you can have lists within lists 'within' a single quote


2]> '(my 3 "sons" (james peter paul))
(MY 3 "sons" (JAMES PETER PAUL))

list is a *function* that creates lists from its arguments.


Note: list is a *function* so its arguments are evaluated

[3]> (list 'my (+ 2 1) "sons")


(MY 3 "sons")

(KEY) A remarkable feature of lisp is that *programs are expressed as lists* (_


programs are *literal* datastructures = "homoiconicity level 1")
If a list is *not* quoted, it is treated as code, and evaluated. (_ If it *is*
quoted it is 'data')

[4]> (list '(+ 2 1) (+ 2 1))


((+ 2 1) 3)

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' )

2.4 List Operations

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.

(cons 'a '(b c d))


(A B C D)

we can build lists by successively consing elements onto an empty list.

(cons 'a (cons 'b (cons 'c '())))


(A B C)

the list function we saw before is just a convenient way to cons several things
onto an empty list.

To extract elements from a list, use car and cdr.


car gives the first element, and cdr gives everything after the first element.

[12]> (car '( a b c d))


A
[13]> (cdr '( a b c d))
(B C D)

2.5 Truth

In CL, the symbol t is the default representation of truth.


Like nil, the symbol t evaluates to itself

[14]> t
T

(_ so when you use symbols in your program do not use t !! t is a 'reserved


symbol' like nil)

A function whose return value is intended to be interpreted as a truth value is


called a predicate.
by convention, lisp predicates have names that end in p.

listp is a predicate that returns true if its argument is a list.

[15]> (listp '( 1 2 3))


T
[16]> (listp '())
T
[17]> (listp nil)
T

(_ note the last, nil *is* ())

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:

[28]> (listp nil)


T
[29]> (listp ())

[22]> (> 2 3)
NIL

[30]> (listp (> 2 3))


T

similarly the function null (_ note: not nullp!!) returns true for both the empty
list and nil and false)

[34]> (null nil)


T
[35]> (null ())
T
[36]> (null (> 2 3))
T

Simplest conditional in CL

(if test-exp true-exp false-exp)

e.g:
> (if ( listp ' ( a b c))
(+ 1 2)
(+ 5 6))
3

> (if ( listp 27)


(+ 1 2)
(+ 5 6))
11

Note that the else-clause is optional in which case it is nil

[38]> (if 0 1 2)
1

(_ note: 0 is NOT false)

> (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))))

A symbol used as a placeholder for a value is a *variable*.


When a symbol is used to represent an argument to a function, it is called a
*parameter*.

[1]> (defun our-third (x) (car (cdr (cdr x))))


OUR-THIRD
[2]> (our-third '( a b c d e))
C

Symbols are variable *names* existing in their own right.


Symbols have to be quoted, else they will be treated as variables, and so the
evaluation will try to get the *value* of the variable, given an unquoted symbol.

( a list has to be quoted because otherwise it will be treated as code)

Lisp makes no distinction between a program, a procedure, or a function. There are


only functions (and macros).
If *you* want to consider one of your functions the 'main' function, you can.
Ordinarily, you can call any function from the toplevel.

2.7 Recursion

Functions can call other functions to get work done. Recursion = functions calling
*themselves* to get work done.

(defun our-member (obj lst)


(if (null lst)
nil
(if (eql (car lst) obj)
lst
(our-member obj (cdr lst)))))

;; note the above function returns nil *or* a list.

[11]> (our-member 'b '(a b c d e))


(B C D E)

eql is a predicate that tests whether its two arguments are identical.

2.8 Reading Lisp

Parentheses are unfamiliar to people new to lisp.


Lisp devs read by indentation, not by parenthesis.
Good editors do paren matching (_ pg apparently uses vim to write lisp code).

2.9 Input And Output

A few functions for input and output.

Most general output function in lisp is format.

It takes two or more arguments.


The first indicates *where* the output is to be printed.
The second is a string template.
The third (+) are objects whose printed representations are to be inserted into the
template.

e.g;

[12]> (format t "~A plus ~A equals ~A. ~%" 2 3 (+ 2 3))


2 plus 3 equals 5.
NIL
[13]>

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.

The standard function for input is read.


KEY: When given no arguments it reads 'from the standard place'.

a function that asks the user a question, reads input, and whatever is entered

[3]> (defun askem (s) (format t "~A" s) (read))


ASKEM
[4]> (askem "how old are you?")
how old are you?23
23

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.

This is the first 'side effecting function' we wrote.


When we write functions without side effects, there is no point in having more than
one expression in the function body.

2.10 variables

The let operator


5]> (let ((x 3) (y 2))
(+ x y))
5
[6]>

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.

A version of askem written using let.

(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.

There is another kind of variable, called a global variable that is visible


everywhere, which can be created by giving a symbol and value to defparameter.
'everywhere' except in procedures where we creat a variable of the same name (_
shadowing). to avoid this, by *convention*, global variables begin and end with
asterisks. The below variable name is 'starglobstar'

(defparameter *glob* 99)

Note that the variable name is *not* quoted.

[10]> (defparameter xyz 999)


XYZ
[11]> xyz
999

(_ note that *glob* is a global *variable*).


to define a global *constant* use

[12]> (defconstant limit 1000)


LIMIT

There is no need to give *constants* distinctive names because it will be an error


if the same name is used for a variable.
If you want to check if a given symbol is the name of a *global* variable or
constant, use the predicate boundp
[15]> (boundp 'limit)
T

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.

[16]> (setf *glob* 76)


76
[17]> *glob*
76
[18]> (let ((n 10)) (setf n 2) n)
2

you can create *global* variables implicitly by assigning to them, in a context


where there is no 'shadowing' variable with the same name.

[19]> (setf mymy 2030)


2030
[20]> mymy
2030

We can do more than assign to variables with setf.


The first argument to setf can be an expression as well as a variable name. In such
cases the value of the second argument is assigned to the *place* referred to by
the first.

thus

[21]> (setf x '( a b c))


(A B C)
[22]> (setf (car x) 'n)
N
[23]> x
(N B C)
[24]>

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)

2.12 Functional Programming

Functional Programming == Programming by writing functions that return values, with


no side effects.
It is the dominant paradigm in lisp, and most functions are called for the values
they return, not their side effects.

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]>

To remove something from the list held in x?


In CL this is done with setf

[27]> (setf x (remove 'n x))


(B C)
[28]> x
(B C)

functional programming in CL is essentially programming without using setf and


other things like it.

It is not convenient to avoid side effects entirely, (_ so CL has side effecting


operators).
But you need fewer than you think, and the more side effects you can avoid, the
better.

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

To do something repeatedly, it is sometimes more natural to use iteration vs


recursion.

A typical use of iteration is to create some kind of table.

the do macro is the fundamental iteration operator in CL.


Like let, do can create (_ local?) variables.

The first argument is a list of variable specifications of the form (variable


initial update)
variable is a symbol
initial and update are expressions.
The variable is set to the value of initial.
On each iteration, the value of the variable is set to the value of the update.

The second argument to do is a list of one or more expressions.


the first expression in the list is the stopping condition of the iteraton.
the remaining expressions in the list is evaluated in order, and the value of
the last returned.

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

Recursive variant of show-squares

(defun show-squares (i end)


(if (> i end)
'done
(progn
(format t "~A ~A ~%" i (* i i))
(show-squares (+ i 1) end))))
[15]> (show-squares 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).

Common Lisp has simpler iterator operations for special cases.


To iterate through the elements of a list there is dolist.

dolist takes two arguments.


the first is an argument of the form (variable expression-returning-a-list)
followed by a body of expressions.
The body is evaluated with the variable bound to each element of the list
returned by the expression.

(defun our-length (lst)


(let ((len 0))
(dolist
(obj lst)
(setf len (+ len 1))) ;; note: here obj is not used.
len))

the recursive version is

(defun our-length (lst)


(if (null lst)
0
(+ 1 (our-length (cdr lst)))))
This version is cleaner but CL doesn't have tail recursion, so it is not as
efficient.

2.14 Functions As Objects

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.

(KEY) passing functions as arguments

[6]> (apply #'+ '( 1 2 3))


6

(_ 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

[8]> (funcall #'+ 1 2 3)


6

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

[11]> ((lambda (x y) (+ x y)) 2 3)


5
we can get the function corresponding to a lambda expression by affixing a sharp
quote

[12]> #'(lambda (x y) (+ x y))


#<FUNCTION :LAMBDA (X Y) (+ X Y)>

We can use lambda expressions with funcall

[13]> (funcall #'(lambda (x y) (+ x y)) 2 3)


5

(_ 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)

lambda expressions allow us to use functions without naming them.

What is lambda?

The lambda in lambda expressions is not an operator (_ function or macro?). It is


just a symbol.
In earlier lisps, functions were represented internally as lists, and the only way
to tell a function from an ordinary list was to check if the list started with the
symbol lambda.

We could denote functions without lambda, say by

((x) (+ x 2))

instead of

(lambda (x) (+ x 2))

but lisp programmers were used to beginning functions with lambda, so the tradition
was retained in CL.

2.15 Types

CL has a flexible approach to types.


In many languages when you declare a variable, you have to declare its type.
In CL values have types, not variables. you could imagine every value having an
attached label identifing its type
you don't have to declare types for variables, since a variable can hold the value
of any type.

(_ 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 type t is the supertype of all types so everything is of type t.

The function typep takes a value and a type specifier, and returns true if the
value is of that type.

[14]> (typep 23 'integer)


T
The built in CL types form a hierarchy.

example: the number 23 (_ a value) is of type fixnum, integer, rational, real,


number, atom, and T

[15]> (typep 23 T)
T

2.16 Looking Forward

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.

Richard Gabriel once jokingly referred to C as a language to write Unix with.


We could describe lisp as a language to write lisp with. But this is a different
kind of statement - a language written in itself (_ Many languages are written in
themselves e.g go, even C) is fundamentally different from a language written to
write a specific applications (_ the go functions that define the compiler are not
available to the user of go, they are all compiled into binary and inaccessible)

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.

2. Lisp programs consist of expressions, which are either atoms, or lists of


operators followed by zero or more arguments. Prefix syntax means that operators
can take any number of arguments.

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.

6. In CL, T represents true, and nil represents false. In a logical context,


anything other than nil counts as true.
if is the basic conditional. and and or operators resemble conditionals.

7. Lisp consists (_ mostly) of functions. You can define new ones with defun.

8. A function that calls itslef is a 'recursive function'. It should be thought


of as a process, not a machine.
9. Parentheses are not an issue because lisp devs read and write lisp by
indentation.

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)

14. The basic iteration operator is do.

15. Functions are regular lisp objects-they can be passed as arguments, and
denoted by lambda expressions.

16. In lisp, values have types, not variables.

Exercises:

1. Describe what happens when the following expressions are evaluated.

(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)

(c) (if (listp 1) (+ 1 2) (+ 3 4))


answer: 7
verify
[3]> (if (listp 1) (+ 1 2) (+ 3 4))
7

(d) (list (and (listp 3) 2) (+ 1 2))


answer: (nil 3)
verify
[4]> (list (and (listp 3) 2) (+ 1 2))
(NIL 3)
note: caps for NIL!

2. Give three distinct cons expressions that return (a b c)

6]> (cons 1 (cons 2 (cons 3 ())))


(1 2 3)
[7]> (cons 1 (cons 2 '(3)))
(1 2 3)
[8]> (cons 1 '(2 3))
(1 2 3)

3. Using car and cdr write a function that returns the fourth element of a list

(defun our-fourth (lst)


(car (cdr (cdr (cdr lst)))))

[10]> (our-fourth '( 1 2 3 4 5 6))


4

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

5. What do these functions do?

(defun enigma (x)


(and (not (null x))
(or (null (car x))
(enigma (cdr x)))))

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

[20]> (enigma '(1 2 3 4))


NIL
[21]> (enigma '())
NIL
[22]> (enigma '(1 nil 2))
T
[23]> (enigma '(nil nil 2))
T
[24]> (enigma '(nil))
T

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

overall this finds the position of x in (list y)

Problem 6:

What would occur in the place of x in each of the following exchanges.

(a) (car (x (cdr '(a (b c) d))))


B
answer: car

verify:

[34]> (car (car (cdr '(a (b c) d))))


B

(b) (x 13 (/ 1 0))
13

answer: or (because x cannot be a function, else (/ 1 0) will be evaluated.


so it is a macro/special form.
It should stop at 13, so or (Note: or works on numbers also since every non nil
value is logically true)

(c) (x #'list 1 nil)


(1)

funcall is the wrong answer. apply is the correct answer (Nil also works as empty
list)

[35]> (funcall #'list 1 nil)


(1 NIL)
[36]> (apply #'list 1 nil)
(1)

but

(list 1 nil) which i thought would be equal to [36] gives


gives
(1 NIL)
what is the direct equivalent of (apply #'list 1 nil)

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

(defun has-list-member (lst)


(if (null lst)
nil
(if (listp (car lst))
T
(has-list-member (cdr lst)))))

[9]> (has-list-member ())


NIL
[12]> (has-list-member '(1 2 (3 4)))
T
[13]> (has-list-member '(1 2 3))
NIL

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)))))

[25]> (count-a '())


0
[26]> (count-a '(1 2 3))
0
[27]> (count-a '(b c d))
0
[28]> (count-a '(a b c d))
1
[29]> (count-a '( b c d a))
1
[30]> (count-a '( b c a d a))
2

8(b) iterative
(defun count-a (lst)
(let ( (cnt 0) )
(dolist (obj lst)
(if (eql obj 'a)
(setf cnt (+ 1 cnt))))
cnt))

[32]> (count-a '())


0
[33]> (count-a '(1 2 3))
0
[34]> (count-a '(b c d))
0
[35]> (count-a '(a b c d))
1
[36]> (count-a '( b c d a))
1
[37]> (count-a '( b c a d a))
2

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.

if we run the original,

[40]> (apply #'+ '(1 nil 2))

*** - +: NIL is not a number

fix

(defun summit (lst)


(setf lst (remove nil lst))
(apply #'+ lst))
and then
[46]> (summit '( 1 nil 2 nil))
3

9(2)

friends version 2

(defun summit (1st)


(let ( (x (car 1st)) )
(if (null x)
(summit (cdr 1st))
(+ x (summit (cdr 1st))))))

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:

(defun summit (lst)


(if (null lst)
0
(let ( ( x (car lst) ) )
(if (null x)
(summit (cdr lst))
(+ x (summit (cdr lst)))))))

50]> (summit '())


0
[51]> (summit '(1))
1
[52]> (summit '(3))
3
[53]> (summit '(3 nil))
3
[54]> (summit '(nil 3 nil))
3
[55]> (summit '(nil 3 4 5 nil 6 nil))
18

You might also like