Lisp EN -- Laboratory 4 -- 2006-2007 -- info.uvt.ro
Lisp EN -- 2006-2007 -- info.uvt.ro
- Lisp EN -- Laboratory 1 -- 2006-2007 -- info.uvt.ro
- Lisp EN -- Laboratory 2 -- 2006-2007 -- info.uvt.ro
- Lisp EN -- Laboratory 3 -- 2006-2007 -- info.uvt.ro
- Lisp EN -- Laboratory 4 -- 2006-2007 -- info.uvt.ro
- Lisp EN -- Laboratory 5 -- 2006-2007 -- info.uvt.ro
- Lisp EN -- Laboratory 6 -- 2006-2007 -- info.uvt.ro
- Lisp EN -- Laboratory 7 -- 2006-2007 -- info.uvt.ro
- Lisp EN -- Test -- 2006-2007 -- info.uvt.ro
Input / output
editIt is used to output at the console the representation of its argument.
If used directly in the interpreter we could see the value printed twice:
- One is the data written to the console by the print function.
- One is the same data written to the console by the interpretor, as the value resulted from evaluating the given expression, as the return value of print is the printed value.
(print <value>) => <value>
(print 1) => 1 (print '(1 2 3 4)) => (1 2 3 4) (print "abc") => "abc"
It is used to read and parse the data from the console.
It takes no arguments and reads exactly one object.
By one object we understand a number, string, symbol, list, etc. In a word whatever can be written to the interpretor can be read with this function.
(read) => <parsed-read-value>
Other input / output functions
edit
Returning multiple values
editThere are cases when we want to return multiple values from a function.
To obtain this we use the function values which takes any number of arguments and returns a special structure which holds all the given values.
(values <value-1> ... <value-n>) => <value1>; ...; <value-n>
(values 1 2 3) => 1; 2; 3
(defun prod-div (a b) (values (* a b) (/ a b))) (prod-div 1 2) => 2; 1/2 (prod-div 100 5) => 500; 20
Functions returning multiple values
edit(floor 1.5) => 1; 0.5 (round 1.5) => 2; -0.5
If we are using a function which return multiple values (through values) we must use multiple-value-bind form to bind each value to a set of variables.
If we use that function without using multiple-value-bind, only the first value is considered, the rest being ignored.
(multiple-value-bind (<name-1> ... <name-n>) <function-call-returning-multiple-values> <statement-1> ... <statement-n>) => <statement-n>
(multiple-value-bind (a b) (floor 1.5) (list a b)) => (1 0.5)
Other multiple value forms
edit
Conditional forms
edit
Grouping forms
editprogn is used to group multiple statements together. The value returned by this form is the value returned by the last statement.
(progn <statement-1> ... <statement-n>) => <statement-n>
(progn (setq a 1) (setq b 2) (+ a b)) => 3
prog1 and prog2 are similar with progn except that the value returned by each one is the value returned by the first, respectively the second statement.
(prog1 <statement-1> ... <statement-n>) => <statement-1> (prog2 <statement-1> <statement-2> ... <statement-n>) => <statement-2>
(prog1 1 2 3 4) => 1 (prog2 1 2 3 4) => 2 (progn 1 2 3 4) => 4
let and let* are used to create a lexical scope in which the given variables are bound to the given initial values.
The value returned by both forms is the value returned by the last statement.
The difference between let and let* is how they execute the initial-value expressions. let executes them in parallel, and let* executes them sequencialy.
(let ((<variable-1> <initial-value-1>) ... (<variable-n> <initial-value-n>)) <statement-1> ... <statement-n>) => <statement-n>
(let* ((<variable-1> <initial-value-1>) ... (<variable-n> <initial-value-n>)) <statement-1> ... <statement-n>) => <statement-n>
(setq a "a-is-1") (setq b "b-is-2") (print a) => "a-is-1" (print b) => "b-is-2" (let ((a b)) (print a) => "b-is-2" (print b)) => "b-is-2" (print a) => "a-is-1"
(setq a "a-is-1") (setq b "b-is-2")
(let ((a b) (b a)) (print a) => "b-is-2" (print b)) => "a-is-1" (let* ((a b) (b a)) (print a) => "b-is-2" (print b)) => "b-is-2"
Other grouping forms
edit
Iterative forms
editdolist is used to iterate a list (at the first level).
The value returned by the form is the value of the return-value expression. This is optional, and in case it is not given it returns nil.
(dolist (<variable> <list> [return-value]) <statement-1> ... <statement-n>) => <return-value> or nil
The following examples shows how we can print the contents of a list:
(defun print-list (l) (dolist (e l) (print e))) (print-list '(1 2 3 4))
If we want to sum the values in a list we can do:
(defun sum-list (l) (let ((sum 0)) (dolist (e l sum) (setq sum (+ sum e))))) (sum-list '(1 2 3 4)) => 10
dotimes is used to iterate over a sequence starting with 0 until a given upper bound with a step of 1.
Like in the case of dolist the value returned is given by the return-value expression, or if missing nil.
(dotimes (<variable> <upper-bound> [return-value]) <statement-1> ... <statement-n>) => <return-value> or nil
(dotimes (i 5) (print i)) => 0 1 2 3 4 (dotimes (i 5.1) (print i)) => 0 1 2 3 4 5
Implementing the factorial function with dotimes would be:
(defun n! (n) (let ((f 1)) (dotimes (i n f) (setq f (* f (1+ i)))))) (n! 4) => 24 (n! 50) => 30414093201713378043612608166064768844377641568960512000000000000
do and do* are the most complex iterative forms.
Just like let and let*, the difference between do and do* is that do evaluates the initial-value and next-value expressions in parallel, meanwhile do* executes them sequentially.
(do ((<variable-1> <initial-value-1> <next-value-1>) ... (<variable-n> <initial-value-n> <next-value-n>)) (<termination-condition> <return-value>) <statement-1> ... <statement-n>)
Fibonacci function could be written with do as:
(defun fibonacci (n) (do ((i 1 (1+ i)) (a1 0 a2) (a2 1 (+ a1 a2))) ((= i n) a1) (print i) ) ) (fibonacci 1) => 0 (fibonacci 2) => 1 (fibonacci 3) => 1 (fibonacci 10) => 34 (fibonacci 100) => 218922995834555169026
Other iterative forms
editSurgical functions
editrplaca and rplacd are used to modify the car, respectively cdr of a pair. (A pair is the result of cons.)
The value returned by these functions is the given pair.
These functions can be used to build circular lists.
(rplaca <pair> <new-car-value>) => <pair> (rplacd <pair> <new-cdr-value>) => <pair>
(setq c (cons 1 2)) (print c) => 1 . 2 (rplaca c 3) (print c) => 3 . 2 (rplacd c 4) (print c) => 3 . 4
(setq l '(1 2 3)) (rplaca (car l) l) => ? (rplacd (cdr l) l) => ? (rplacd (cddr l) l) => ?
Other surgical functions
editThe following functions are used just like their counterparts, except that they modify the given list instead of creating a new one.
(setq l '(1 2 3 4 5)) (print (reverse l)) => (5 4 3 2 1) (print l) => (1 2 3 4 5) (print (nreverse l)) => (5 4 3 2 1) (print l) => (5 4 3 2 1)
Other modification forms
edit
Assignment 4
editThis assignment is due next Wednesday (2007-03-28) at 24:00, and should be sent by email.
When you send the email please include in the subject [LISP-EN-2] First_name Last_name for the second year and [LISP-EN-3] First_name Last_name for the third year. Please paste the code inside the email, DO NOT ATTACH any files.
Write 6 functions:
- 2 functions using dolist
- 2 functions using dotimes
- 2 functions using do or do*
The functions must be followed by 2 or 3 representative test cases.
The functions must be different than the ones presented at the laboratory.
Ciprian Dorin Craciun
2007-03-22