The Case primitive: matches the evaluated key form against the unevaluated keys by using eql The general format of case is the following: (case (... ).....

Slides:



Advertisements
Similar presentations
Lisp Control and Data Structures CIS 479/579 Bruce R. Maxim UM-Dearborn.
Advertisements

09 Examples Functional Programming. Tower of Hanoi AB C.
CS 63 LISP Philip Greenspun's Tenth* Rule of Programming:
Lisp. Versions of LISP Lisp is an old language with many variants Lisp is alive and well today Most modern versions are based on Common Lisp LispWorks.
C-LISP. LISP 2 Lisp was invented by John McCarthy in 1958 while he was at the Massachusetts Institute of Technology (MIT).John McCarthyMassachusetts Institute.
Functional Programming. Pure Functional Programming Computation is largely performed by applying functions to values. The value of an expression depends.
1 Programming Languages and Paradigms Lisp Programming.
List manipulation Consider student database, where each student is represented by the following list: * (setf student1 '((Paul Bennett) ((hw1 4.3) (hw2.
1 COSC3306: Programming Paradigms Lecture 11: Applicative Programming with Lisp Haibin Zhu, Ph.D. Computer Science Nipissing University (C) 2003.
1 Introduction of Lisp function e.g. (+ 2 2) Shift+Enter Execute …… (+ 1 2) 3 ( ) 15 (- 1 6) -5 ( ) -5 (- ( ) (+
Lisp – Introduction יעל נצר מערכות נבונות סמסטר ב' תשס"ו.
Lisp Recitation (cse471/598 Fall 2007 ) Aravind Kalavagattu.
Functional Programming COMP2003 A course on functional programming using Common Lisp Dr Eleni Mangina
Procedures with optional parameters which do not require matching arguments Example: consider the exponent function which may take one argument, m, in.
ITERATIVE CONSTRUCTS: DOLIST Dolist is an iterative construct (a loop statement) consisting of a variable declaration and a body The body states what happens.
Lisp. Versions of LISP Lisp is an old language with many variants –LISP is an acronym for List Processing language Lisp is alive and well today Most modern.
Common Lisp! John Paxton Montana State University Summer 2003.
LISP primitives on sequences FIRST (or CAR) and REST (or CDR) take lists apart. Consider the list (First day of the semester). * (first '(First day of.
CMSC 471 LISP. Why Lisp? Because it’s the most widely used AI programming language Because it’s good for writing production software (Graham article)
Programming in Lisp; Instructor: Alok Mehta Programming in Lisp Recursion, Data Abstraction, Mapping, Iteration.
It is suggested that you use the Lisp interpreter available on the general machine (general.asu.edu). You are welcome to use other interpreters while developing,
Functional Programming COMP2003 A course on functional programming using Common Lisp Dr Eleni Mangina
COMP 205 – Week 11 Dr. Chunbo Chu. Intro Lisp stands for “LISt Process” Invented by John McCarthy (1958) Simple data structure (atoms and lists) Heavy.
LISP 1.5 and beyond A very quick tour. Data Atoms (symbols) including numbers – All types of numbers including Roman! (well, in the early days) – Syntactically.
TUTORIAL 2 CSCI3230 ( First Term) By Paco WONG 1.
F UNCTIONAL P ROGRAMMING 05 Functions. F UNCTIONS - G LOBAL F UNCTIONS fboundp Tells whether there is a function with a given symbol as its name > (fboundp.
Allegro CL Certification Program Lisp Programming Series Level I Session Top Ten Things to Know.
Yu-Tzu Lin ( 林育慈 )
For Wednesday Read Chapter 4, sections 1 and 2 Homework: –Lisp handout 3.
Alok Mehta - Programming in Lisp - Data Abstraction and Mapping Programming in Lisp Data Abstraction and Mapping.
C++ Programming: From Problem Analysis to Program Design, Third Edition Chapter 17: Recursion.
For Monday Read Chapter 3 Homework: –Lisp handout 2.
1 Lisp Functions –Built-in functions –Defining functions –Function Evaluation and Special Forms defun, if Control statements –Conditional if, cond –Repetition.
Common lisp A functional programming language. Useful URL:
CSE 341, S. Tanimoto Lisp Defining Functions with DEFUN Functions are the primary abstraction mechanism available in Lisp. (Others are structures.
Iteration Chapters 6 & 7. Iteration in LISP n LISP (unlike Prolog) allows iteration –mapcar, remove-if(-not), count-if, find-if for special purpose iteration.
CSCI 2210: Programming in Lisp
The Loop Macro Many of the CL “functions” are actually macros (let, progn, if, etc) The most complicated macro in CL is probably the Loop macro –The Loop.
Basic LISP Programming Common LISP follows the algorithm below when interacting with users: loop read in an expression from the console; evaluate the expression;
Function Design in LISP. Program Files n LISP programs are plain text –DOS extensions vary; use.lsp for this course n (load “filename.lsp”) n Can use.
LISP Data Types Functional Programming Academic Year Alessandro Cimatti
Building user-defined functions: the progressive envelopment technique The idea: define combinations of LISP primitives through a sequence of experiments.
Introduction to LISP. Lisp Extensible: It lets you define new operators yourself Lisp programs are expressed as lisp data structures –You can write programs.
UMBC CMSC Common Lisp II. UMBC CMSC Input and Output Print is the most primitive output function > (print (list 'foo 'bar)) (FOO BAR) The.
PRACTICAL COMMON LISP Peter Seibel 1.
Control in LISP More on Predicates & Conditionals.
Milos Hauskrecht (PDF) Hieu D. Vu (PPT) LISP PROGARMMING LANGUAGE.
1 Variable Declarations Global and special variables – (defvar …) – (defparameter …) – (defconstant …) – (setq var2 (list 4 5)) – (setf …) Local variables.
Basic Introduction to Lisp
Control Structures CSC 358/ Outline Midterm Lab #3 Homework #4 Sequential structures Conditional structures Unconditional branching Iteration.
Search as a problem solving technique. Consider an AI program that is capable of formulating a desired goal based on the analysis of the current world.
1 Outline Review Introduction to LISP Symbols and Numbers Lists Writing LISP Functions LISPWorks.
Section 15.4, 15.6 plus other materials
Example of formula (defun roots (a b c) (list
Modern Programming Languages Lecture 20 Fakhar Lodhi
Getting Started with Lisp
Using Lisp Lisp is a interactive system
Allegro CL Certification Program
Modern Programming Languages Lecture 20 Fakhar Lodhi
The Metacircular Evaluator (Continued)
LISP A brief overview.
John McCarthy Pioneer in AI Also Lisp Formalize common-sense reasoning
Defining Functions with DEFUN
Abstraction and Repetition
Common Lisp II.
Programming Languages
The general format of case is the following: (case <key form>
List manipulation Consider student database, where each student is represented by the following list: * (setf student1 '((Paul Bennett) ((hw1 4.3) (hw2.
LISP primitives on sequences
Procedures with optional parameters which do not require matching arguments Example: consider the exponent function which may take one argument, m, in.
Presentation transcript:

The Case primitive: matches the evaluated key form against the unevaluated keys by using eql The general format of case is the following: (case (... )..... (... )) Example: * (setf object 'sphere r 2) 2 * (case object (circle (* pi r r)) (sphere (* 4 pi r r)))

The key may be an atom or a list; in the latter case the list is searched for the key by means of the member predicate Example: * (case object ((circle wheel) (* pi r r)) ((ball sphere) (* 4 pi r r)) (otherwise 0)) ; if none of the clauses is triggered, case ; returns NIL, the otherwise clause (or t) ; can be used to set the returned value.

The problem reduction technique Divide the problem into sub-problems each of which can be handled separately. Example: the both-ends procedure (defun both-ends (whole-list) (case (length whole-list) (0....) ==> (0 nil) (1....) ==> (1 (cons (first whole-list) whole-list)) (2....) ==> (2 whole-list) (t....))) ==> (t (cons (first whole-list) (last whole-list)))))

The procedure abstraction technique: arrange procedures into “abstraction” layers. Example: the both-ends procedure * (defun both-ends (whole-list) (make-list (get-first-el whole-list) (get-last-el whole-list))) BOTH-ENDS * (defun make-list (el-1 el-2) (list el-1 el-2)) MAKE-LIST * (defun get-first-el (list-1) (first list-1)) GET-FIRST-EL * (defun get-last-el (list-1) (first (last list-1))) GET-LAST-EL

Defvar and defparameter define global variables (defvar *global*) declares *global* as a global variable. (defvar *global* expression) assigns a value to *global* (defparameter *global* expression) declares *global* as a global variable, and assings a value to it. Examples: * (defvar *var-1*) * (defparameter *par-1*) *VAR-1* ERROR * (defvar *var-1* 222) * (defparameter *par-1* 77) *VAR-1* 77 * *var-1* * *par-1* * (defvar *var-1* 333) * (defparameter *par-1* 88) *VAR-1* *PAR-1* * *var-1* * *par-1*

Singly recursive procedures: each recursive call originates only one new call Example: compute the “n” power of m. * (defun exponent (m n) (if (zerop n) 1 (* m (exponent m (- n 1))))) EXPONENT * (exponent 2 3) 8 The behavior of recursive procedures can be observed by means of the trace primitive. Untrace will undo the effect of trace. These have the following syntax: (trace ) (untrace )

* (trace exponent) (EXPONENT) * (exponent 2 3) | 1 Entering: EXPONENT, argument-list: (2 3) | 2 Entering: EXPONENT, argument-list: (2 2) | | 3 Entering: EXPONENT, argument-list: (2 1) | | 4 Entering: EXPONENT, argument-list: (2 0) | | 4 Exiting: EXPONENT, value 1 | | 3 Exiting: EXPONENT, value 2 | 2 Exiting: EXPONENT, value 4 | 1 Exiting: EXPONENT, value 8 8

Doubly recursive procedures: each call originates two recursive calls Example: compute Fibonacci numbers * (defun fibonacci (n) (if (or (= n 0) (= n 1)) 1 (+ (fibonacci (- n 1)) (fibonacci (- n 2))))) FIBONACCI * (fibonacci 5) 8 * (trace fibonacci) (FIBONACCI)

* (fibonacci 5) | 1 Entering: FIBONACCI, argument-list: (5) | 2 Entering: FIBONACCI, argument-list: (4) | | 3 Entering: FIBONACCI, argument-list: (3) | | 4 Entering: FIBONACCI, argument-list: (2) | | | 5 Entering: FIBONACCI, argument-list: (1) | | | 5 Exiting: FIBONACCI, value 1 | | | 5 Entering: FIBONACCI, argument-list: (0) | | | 5 Exiting: FIBONACCI, value 1 | | 4 Exiting: FIBONACCI, value 2 | | 4 Entering: FIBONACCI, argument-list: (1) | | 4 Exiting: FIBONACCI, value 1 | | 3 Exiting: FIBONACCI, value 3 | | 3 Entering: FIBONACCI, argument-list: (2) | | 4 Entering: FIBONACCI, argument-list: (1) | | 4 Exiting: FIBONACCI, value 1 | | 4 Entering: FIBONACCI, argument-list: (0) | | 4 Exiting: FIBONACCI, value 1 | | 3 Exiting: FIBONACCI, value 2 | 2 Exiting: FIBONACCI, value 5 | 2 Entering: FIBONACCI, argument-list: (3) | | 3 Entering: FIBONACCI, argument-list: (2) | | 4 Entering: FIBONACCI, argument-list: (1) | | 4 Exiting: FIBONACCI, value 1 | | 4 Entering: FIBONACCI, argument-list: (0) | | 4 Exiting: FIBONACCI, value 1 | | 3 Exiting: FIBONACCI, value 2 | | 3 Entering: FIBONACCI, argument-list: (1) | | 3 Exiting: FIBONACCI, value 1 | 2 Exiting: FIBONACCI, value 3 | 1 Exiting: FIBONACCI, value 8 8

Tail recursive procedures: a way to make recursion efficient Example: compute the number of elements in a list (version 1) * (defun count-elements-1 (list-1) (if (endp list-1) 0 (+ 1 (count-elements-1 (rest list-1))))) COUNT-ELEMENTS-1 * (setf list-1 '(a b c d)) * (count-elements-1 list-1) | 1 Entering: COUNT-ELEMENTS-1, argument-list: ((A B C D)) | 2 Entering: COUNT-ELEMENTS-1, argument-list: ((B C D)) | | 3 Entering: COUNT-ELEMENTS-1, argument-list: ((C D)) | | 4 Entering: COUNT-ELEMENTS-1, argument-list: ((D)) | | | 5 Entering: COUNT-ELEMENTS-1, argument-list: (NIL) | | | 5 Exiting: COUNT-ELEMENTS-1, value 0 | | 4 Exiting: COUNT-ELEMENTS-1, value 1 | | 3 Exiting: COUNT-ELEMENTS-1, value 2 | 2 Exiting: COUNT-ELEMENTS-1, value 3 | 1 Exiting: COUNT-ELEMENTS-1, value 4 4

Tail recursion (cont.) Example: compute the number of elements in a list (version 2) * (defun count-elements-2 (list-1) (count-elements-2-aux list-1 0)) COUNT-ELEMENTS-2 * (defun count-elements-2-aux (list-1 result) (if (endp list-1) result (count-elements-2-aux (rest list-1) (+ 1 result)))) COUNT-ELEMENTS-2-AUX * (count-elements-2 list-1) | 1 Entering: COUNT-ELEMENTS-2-AUX, argument-list: ((A B C D) 0) | 2 Entering: COUNT-ELEMENTS-2-AUX, argument-list: ((B C D) 1) | | 3 Entering: COUNT-ELEMENTS-2-AUX, argument-list: ((C D) 2) | | 4 Entering: COUNT-ELEMENTS-2-AUX, argument-list: ((D) 3) | | | 5 Entering: COUNT-ELEMENTS-2-AUX, argument-list: (NIL 4) | | | 5 Exiting: COUNT-ELEMENTS-2-AUX, value 4 | | 4 Exiting: COUNT-ELEMENTS-2-AUX, value 4 | | 3 Exiting: COUNT-ELEMENTS-2-AUX, value 4 | 2 Exiting: COUNT-ELEMENTS-2-AUX, value 4 | 1 Exiting: COUNT-ELEMENTS-2-AUX, value 4 4

The Tower of Hanoi example Version 1: uses a doubly recursive procedure. * (defun tower-of-hanoi-1 (list-of-disks) (if (endp list-of-disks) 0 (+ (tower-of-hanoi-1 (rest list-of-disks)) 1 (tower-of-hanoi-1 (rest list-of-disks))))) TOWER-OF-HANOI-1 Version 2: uses a singly recursive procedure. * (defun tower-of-hanoi-2 (list-of-disks) (if (endp list-of-disks) 0 (+ 1 (* 2 (tower-of-hanoi-2 (rest list-of-disks)))))) TOWER-OF-HANOI-2

Iteration control structure: the DOTIMES primitive Dotimes supports iteration on numbers. It has the following format: (dotimes ( ) ) When dotimes is entered, the upper-bound form is evaluated resulting in a number, say n. Numbers between 0 and n-1 are assigned to the count parameter one by one, and for each one of these numbers the body is evaluated. Finally, the result form is evaluated, and its value is returned by dotimes (if the result form is missing, dotimes returns NIL).

Example: compute the “n” power of m. * (defun exponent-2 (m n) (let ((result 1)) (dotimes (count n result) (setf result (* m result)) ))) (print result) EXPONENT-2 * (trace exponent-2) (EXPONENT-2) * (exponent-2 3 3) | 1 Entering: EXPONENT-2, argument-list: (3 3) ; trace is not very useful here. | 1 Exiting: EXPONENT-2, value 27 ; Incorporating print forms to see 27 ; intermediate results is better.

Dolist supports iteration on lists. Its format is the following: (dolist ( ) ) When dolist is entered, the list form is evaluated returning a list of elements. Each one of them is assigned to the element parameter, and the body is evaluated. Finally, the result form is evaluated, and its value is returned by dolist (if the result form is missing, dolist returns NIL). Iteration control stucture: the DOLIST primitive

Example: count number of a’s in a list. * (defun count-a (list-1) (let ((result 0)) (dolist (element list-1 result) (when (eql element 'a) (setf result (+ 1 result)))))) COUNT-A * (setf list-1 '(a s d f a s d w a a)) (A S D F A S D W A A) * (count-a list-1) 4

DOTIMES and DOLIST can be terminated by the (return ) form Whenever (return ) is encountered, dotimes/dolist terminates and returns the value of. Example: does the list contain at least “n” a’s? If yes, return them as soon as they are found. * (defun find-n-a (n list-1) (let ((result 0) (a-list nil)) (dolist (element list-1 a-list) (cond ((<= n result) (return a-list)) ((eql element 'a) (setf result (+ 1 result)) (setf a-list (cons element a-list))))))) FIND-N-A * (find-n-a 2 list-1) (A A)

The DO primitive works on both numbers and lists, and is more general than DOTIMES and DOLIST Do has the following format: (do (( ) ( ) ….. ( )) ( ) ) When do is entered, its parameters are set to their initial values in parallel (in the same way as in the let form). If there are no parameters, an empty parameter list must be provided. The termination test is evaluated always before the body is evaluated. If it succeeds, intermediate forms and the result form are evaluated; the value of the result form is returned by do (if no result form is given, do returns NIL).

Example: compute “n” power of m Version 1: * (defun exponent-3 (m n) (do ((result 1) (exponent n)) ((zerop exponent) result) (setf result (* m result)) (setf exponent (- exponent 1)))) EXPONENT-3 * (exponent-3 3 3) 27 Version 2: * (defun exponent-4 (m n) (do ((result 1) (exponent n)) ( ) (when (zerop exponent) (return result)) (setf result (* m result)) (setf exponent (- exponent 1)))) EXPONENT-4 * (exponent-4 3 3) 27

DO* assigns initial values to parameters sequentially (like let*) Example which does not work * (defun exponent-5 (m n) (do ((result m (* m result)) (exponent n (- exponent 1)) (counter (- exponent 1) (- exponent 1))) ((zerop counter) result))) EXPONENT-5 * (exponent-5 3 3) *** Debugger warning: leftover specials *** >>> Error: {Determining function in error.} >>> Error:Unbound variable: EXPONENT (#...) DO* solves the problem. * (defun exponent-6 (m n) (do* ((result m (* m result)) (exponent n (- exponent 1)) (counter (- exponent 1) (- exponent 1))) ((zerop counter) result))) EXPONENT-6 A better solution: * (defun exponent-7 (m n) (do* ((result 1 (* m result)) (exponent n (- exponent 1)) (counter exponent (- counter 1))) ((zerop counter) result))) EXPONENT-7

The LOOP primitive implements infinite loop if (return ) is not encountered Loop has the following format: (loop ) Example: count the number of elements in a list. * (setf list-1 '(a b c d e)) (A B C D E) * (setf count-elements 0) 0 * (loop (when (endp list-1) (return count-elements)) (setf count-elements (+ 1 count-elements)) (setf list-1 (rest list-1))) 5

The PROG1 and PROGN primitives allow several forms to be viewed as a group in which forms are evaluated sequentially. n Prog1 has the following form: (prog1 … ). All forms are evaluated, and prog1 returns the value of the first form. n Progn has the following form: (progn … ). All forms are evaluated, and progn returns the value of the last form. Example: * (prog1 (eql 'a 'a) (setf a 5)) T * (progn (eql 'a 'a) (setf a 5)) 5

The FORMAT primitive: produces more elegant printing than PRINT Example: * (format t "Hi there!")Hi there! ; the t argument says that the output should be ; printed at the terminal. The returned value is NIL ; NIL To print a string on a new line, the ~% directive should be placed at the beginning of the string: * (format t "~%Hi there!") Hi there! NIL The TERPRI primitive also moves the cursor to a new line. For example: * (prog1 (terpri) (format t "Hi")) Hi NIL The ~& directive tells format to print on a new line, if it is not already on a new line, while the ~a directive tells format to insert the value of an additional argument which appears after format’s string.

More examples * (progn (format t "~%Student name: ~a" name) (format t "~&Major: ~a" major)) Student name: ANNA Major: CS NIL * (format t "~%Student name: ~10a Major: ~10a" name major) Student name: ANNA Major: CS NIL * (format t "~%Student name: ~20a Major: ~10a" name major) Student name: ANNA Major: CS NIL

The Read primitive reads a value from the keyboard Examples: * (read)hello ; the input is typed immediately after read. HELLO * (setf greetings (read))hi ; the input can be assigned to a variable. HI * greetings HI * (setf greetings (read))(hi there!) ; if the input contains more (HI THERE!) ; than one symbol it must be enclosed in a list. * greetings (HI THERE!)

Print and read used in combination allow for a more informative dialog Example: * (prog1 (print '(Please enter your name)) (setf name (read)) (print (append '(hi) (list name) '(how are you today?)))) (PLEASE ENTER YOUR NAME) neli (HI NELI HOW ARE YOU TODAY?) (PLEASE ENTER YOUR NAME) * name NELI Do not use “:” in the print argument; for example, name: will be understood as a reference to a package which does not exist and will result in an error.

Read, Terpri and Format in combination can also be used for a more informative dialog Example: * (prog1 (terpri) (format t "Please enter your name : ") (setf name (read)) (terpri) (format t "Hi ~a how are you today?" name)) Please enter your name : neli Hi NELI how are you today? NIL Notice the space between “name” and “:” in the format statement.