Download LISP

Document related concepts

Tail call wikipedia , lookup

Currying wikipedia , lookup

Combinatory logic wikipedia , lookup

Falcon (programming language) wikipedia , lookup

Lambda calculus wikipedia , lookup

Lambda calculus definition wikipedia , lookup

Anonymous function wikipedia , lookup

Closure (computer programming) wikipedia , lookup

Lambda lifting wikipedia , lookup

Common Lisp wikipedia , lookup

Lisp (programming language) wikipedia , lookup

Standard ML wikipedia , lookup

Lecture 4
John McCarthy and Marvin Minsky formed MIT’s AI Project
in 1958.
McCarthy developed LISP in 1958 –1959.
Suggested reading: John McCarthy’s home page
Books in UBE library
1. Common LISP by Guy Steele Jr. (254)
2. Common LISP and Artificial Intelligence by Pattrick
R. Harrison (144)
Functional Programming
• Imperative languages are based on Von Newman
• Functional programming paradigm is based on
mathematical functions.
• Mathematical function is mapping of members of one set,
called the domain set, to another set called the range set.
F(x) = 2x + 5
Functional Programming
• Evaluation is controlled by recursion and conditional
expressions rather than by sequencing and iterative
repetition that are common to imperative languages.
• Imperative languages refer to values stored in memory
locations, so side effects are generated.
• In mathematical functions there are no variables in
the sense of imperative languages, so there can be
no side effect.
Functional Programming
• Naming a function can be separated from defining a
function. Lambda notation is devised to define a nameless
(((x) x*x*x) (2))
Functional Forms
• A high order function, is one that either takes functions as
parameters or yields a function as its results, or both.
Function composition
f(x)  x + 2
g(x)  x * 3
h(x)  f(g(x)), or h(x)  (3 * x) + 2
Functional Forms
• Is a functional form that takes a list of functions as
parameters and collects the results in a list.
f(x)  x * x
g(x)  x * 3
h(x)  x / 2
[f, g, h](4) yields (16, 12, 2)
Functional Forms
• Is a functional form that takes a single function as a
parameter and applies it to a list of arguments.
h(x)  x * x
(h, (2, 3, 4)) yields (4, 9, 16)
Fundamentals of Functional Programming
In imperative programming an expression is evaluated and
the result is stored in memory location which is represented
as a variable in the program.
A purely functional programming language does not use
variables and assignment statements. Without variables iterative
constructs are not possible. Repetition must be done by
The execution of a function always produces the same result
when given the same parameters. This is called referential
Fundamentals of Functional Programming
Although functional languages are often implemented with
interpreters, they can also be compiled.
Functions in imperative languages have restrictions on the types
of values that can be returned. In many languages only scalar
types are allowed. More importantly, they can not return a
Imperative languages may have functional side effects.
• LISP was the first functional programming language.
• With the exception of the first version all LISP dialects
include imperative language features such as, imperative
style variables, assignment statements, and iteration.
Symbolic Expressions, the Syntactic Basis
• The syntactic elements of the LISP programming language are
symbolic expressions.
• Both programs and data are represented as s-expressions. An sexpression may be either an atom or a list.
• Symbolic atoms are composed of letters numbers and certain nonalphanumeric characters (* - + $ % ^ &_ > < )
• A list is a sequence of either atoms or other lists separated by blanks
and enclosed in parentheses.
• ‘(A B C D)
• ‘(A (B C) D (E (F G)))
(function_name arg_1 … arg_n)
evaluates to 12.
• ‘(1 2 3 4)
• ‘(likes bill ?X)
• (- (+ 3 4) 7)
• (=(+ 2 3) 5)
• (list 1 2 3 4)
(1 2 3 4)
• (nth 0(list a b c d))
Concepts Behind LISP
• From this emerged a universal LISP function that could
evaluate any other function in LISP.
• The first requirement for the universal LISP function was a
notation that allowed functions to be expressed in the same
way data was expressed.
• Function calls were specified in a prefix list form called
Cambridge Polish
• In evaluating a function LISP first evaluates its arguments
and then applies the function indicated by the first element
of the expression to the results of these evaluations. For
example in evaluating the expression
(+ (* 2 3) (* 3 5))
• LISP first evaluates the arguments (* 2 3) and (* 3 5).
These results are then passed to the top level addition
which is evaluated, returning 21.
An s-expression is defined recursively:
1. An atom is an s-expression.
2. If s1, s2,...,sn are s-expressions,
then so is the list (s1, s2,...,sn).
Evaluating an s-expression
• A list is a non-atomic expression.
• In evaluating an s-expression:
– If the s-expression is a number, return the value of the
– If the s-expression is an atomic symbol, return the value
bound to that symbol; if it is not bound then it is an
– If the s-expression is a list, evaluate the second through
the last arguments and apply the function indicated by
the first argument to the result.
Control of LISP Evaluation: quote and eval
The purpose of the quote is to prevent evaluation of sexpression that should be treated as data rather than an
evaluable form.
(quote(a b c ))
(quote(+1 3))
(list(+1 2) (+ 3 4))
(list ‘(+ 1 2) ‘(+ 3 4))
(>(* 5 6) (+ 4 5))
(‘(a b c ))
(‘(+ 1 3))
(3 7)
(a b c)
(+ 1 3 )
((+ 1 2) (+ 3 4))
eval is a complement to quote.
(quote(+ 2 3))
(eval(quote(+ 2 3)))
(+ 2 3)
Programming in LISP: Creating New Functions
LISP supports a large number of built in functions
Arithmetic functions supporting both integers and real numbers.
Program control functions
List manipulation and other data structuring functions.
Input/Output functions
Forms for the control of function evaluation
Functions for the control of the environment and operating system.
(defun square(x)
(* x x))
>(square 5)
; causes 5 to be bound to x
(defun <function name> (<formal parameters>)
(<function body) )
(defun hypotenuse(x y)
(sqrt (+ (square(x)) (square(y))))
Program Control in LISP: Conditionals
and Predicates
cond takes as arguments a number of condition - action pairs.
(<condition1> <action1>)
(<condition2> <action2>)
(<conditionn> <actionn>) )
(defun absolute-value(x)
(cond ((< x 0) (-x))
((> = x 0) (x))))
(defun absolute-value(x)
(cond ((< x 0) (-x))
(t x)))
If clause
if takes three arguments
(defun absolute-value(x)
(if (< x 0 ) (-x) x ))
A predicate is a LISP function that returns nil to indicate ‘false’ and
anything other than nil to indicate ‘true’.
> (= 9 (+ 4 5))
>(oddp 4)
Examples to arithmetic predicates are: <, >, =, oddp, evenp, zerop, plusp,
>(member 3 ‘(1 2 3 4 5))
(3 4 5)
All Boolean functions are short circuit in Common LISP. They
return a value as soon as the result is determined.
>(and(t t nil t))
>(or( t nil t t))
Functions, lists, and Symbolic Computing
Using nth it is possible to define access functions for the various fields of
a data record.
Suppose a record consists of the fields name, salary, employee number.
>(defun name-field(record)
(nth 0 record))
>(name-field ‘((Ada Lovelance) 45000.00 38519))
(Ada Lovelance)
>(defun first-name(name)
(nth 0(name))
>(first-name (name-field ‘((Ada Lovelance) 45000.00 38519)))
list is a built in LISP function.
>(list 1 2 3 4)
(1 2 3 4)
>(defun build-record (name salary emp-number)
(list name salary emp-number))
>(build-record ‘((Ada Lovelance) 45000.00 38519))
(Ada Lovelance) 45000.00 38519)
Using build record and the access functions we may
construct functions that return a modified copy of a record .
(defun replace-salary-field(record new-salary))
(build-record (name-field record)
(number-field record)))
>(replace-salary-field ‘(((Ada Lovelance) 45000.00 38519)
((Ada Lovelance) 50000.00 38519)
Lists as Recursive Structures
The basic functions for accessing the components of a list are
car and cdr.
car (first)
- Takes a list as its argument and returns the
first element of the list.
cdr (rest)
- Takes a list as its argument and returns the
list with the first argument removed.
>(car ’(a b c ))
>(cdr ’(a b c))
(b c)
>(car(cdr ’(a b c d)))
A recursive approach to manipulate list structures to perform
an operation on each of the elements of a list
1. If the list is empty quit
2. Perform the operation on the first element of the list and
recur on the remainder of the list.
Common LISP predicates for list processing are
member : Determines whether an s-expression
is a member of a list.
length : Determines the length of a list.
Define ‘my-member’ which takes an atom and a list
as arguments and returns nil if the atom is not
present in the list, otherwise returns the portion of
the list containing the atom as the first element.
(defun my-member(element list)
(cond((null list) nil)
((equal element(car list)) list)
(t (my-member element (cdr list))))
>(my-member 4 ‘(1 2 3 4 5 6))
(4 5 6)
(defun my-length(list)
(cond((null list) 0)
(t (+ (my-length (cdr list) 1)))))
cons is a basic list constructor
(cons ’A ’(L I S))
(A L I S)
(cons ’A ’B)
(A . B)
(cons ’(A) ’(L I S))
((A) L I S)
(cons ’A (cons ’B (cons ’C ‘D) ) )  (A B C . D)
(defun filter-negatives (number-list)
(cond ((null number-list) nil)
((plusp (car number-list)) (cons (car number-list)
(filter-negatives (cdr number-list))))
(t (filter-negatives (cdr number-list)))))
>filter-negatives ‘(1 -1 2 3 -4 -5 6)
(1 2 3 6)
car and cdr tear lists apart and drive the recursion ; cons
selectively constructs the result as the recursion unwinds.
Recursion is used to scan the list element by element, as the
recursion unwinds the cons function reassembles the solution.
If cons is called with two lists as arguments it makes the
first of these a new first element of the second list,
whereas append returns a list whose elements are the
elements of the two arguments:
>(cons ’(1 2) ‘(4 5 6))
((1 2) 4 5 6))
>(append ’(1 2) ‘(4 5 6))
(1 2 4 5 6)
Lists are powerful representations for tree structures
especially for search and parse trees. In addition nested
lists provide a way of hierarchically structuring complex
(1 2 3 4)
((1 2) 3 4)
car-cdr recursion adds one more dimension to simple cdr
(defun count-atoms (list)
(cond ((null list) 0)
((atom list) 1)
(t (+(count-atoms(car list))
>(count-atoms ‘((1 2 ) 3 (((4 5 (6)))))
Functional Programming
(set ‘inc 0)
(defun f(x)
(set ‘inc(+ inc 1))
(+ x inc))
>(f 4)
>(f 4)
In this example x is a bound variable where inc is a free
All the variables that appear as the formal parameter of a function
are bound variables, and all the other variables that appear in the
body of the function are free variables.
When a function is called any bindings that a bound variable may
have in the global environment are saved and the variable is
rebound to the calling parameter.
After the function has completed execution, the original bindings are
restored. Thus setting the value of a bound variable inside a function
body has no effect on the global bindings of that variable
As it is seen from the example free variables in a
function definition are the primary source of side
effects in functions.
(defun fo(x)
(setq x (+ x 1))
The Assignment of Value
SETQ : The variable is assigned the value of the form.
(SETQ X 23)
;x assigned 23
SET takes only one pair. The first one is a symbol and
the second one is a value. Both arguments are
evaluated and the value of the second argument is
SETF : It is a general form of SETQ. First element is a
memory location rather than a variable name. Place
can refer to locations other than the value cell of
the variable.
The Assignment of Value
(SETF A 100 B 200 C 300 D 400)
>> 100 200 300 400
>> B 200 300 400
(SET A 999)
>> B 999 300 400
;arguments are evaluated
The Assignment of Value
setf regards the first argument as naming a memory location.
>(setf x ‘(a b c))
(a b c)
>(setf(cdr x) ‘(2 3))
(a b c)
(2 3)
>(setf(car x) 1)
(1 2 3)
(1 b c)
Pattern Matching in Lisp
match takes two arguments and returns t if the expressions
match. Matching requires that both expressions have the same
structure as well as having identical atoms in corresponding
>(match ‘(likes bill wine) ‘(likes bill wine))
>(match ‘(likes bill ?) ‘(likes bill wine))
>(match ‘(likes bill ?) ‘(likes ? wine))
High-Order Functions and Procedural Abstraction
Functions that take other functions as parameters or return
them as results are called higher-order functions and
constitute an important tool for procedural abstraction.
(defun filter-evens (number-list)
(cond (null number-list) nil)
((oddp (car number-list))
(cons (car(number-list) (filter-evens (cdr number-list)))
(t (filter-evens (cdr number-list)))))
funcall takes as arguments a function and a series of arguments
and applies that function to those arguments:
>(funcall ‘plus 2 3)
(defun filter (list-of-elements test )
(cond(null list-of-elements) nil)
((funcall test(car number-list))
(cons(car(number-list) (filter (cdr list-of-elements) test))
(t (filter (cdr list-of-elements) test)))))
The function, filter applies the test to the first element of the
list. If the test returns non-nil it conses the element onto the
result of filtering the cdr of the list; oterwise it just returns the
filtered cdr.
>(filter ‘(1 3 -9 5 -2 -7 6) ‘plusp)
>(filter ‘(1 a b c 5 7) ‘numberp)
(1 3 5 6)
(1 5 7)
Another important class of higher-order functions
consists of mapping functions.
>(mapcar ( ‘plus ‘(1 2 3) ‘(2 4 6)))
(3 6 9)
Functional Arguments and Lambda Expressions
Lambda expressions allows the programmer to separate a
function definition from the function name. Without lambda
expressions the programmer must define every function in the
global environment using a defun even though the function may
be used only once.
>(funcall ‘(lambda( x y) (+ (*x x) y)) ( 2 3))
>(mapcar ‘(lambda(x) (* x x)) ‘(1 2 3 4 5))
(1 2 9 16 25)
Data types in Common LISP
Built in types are: integers, floating numbers, strings
and characters. LISP also includes structured types as
arrays, hash tables, sets, and structures .
Unlike other strongly typed languages as Pascal, in Lisp it is
the data objects that are typed rather than variables. Any
LISP symbol may bind to any object; the object itself is
typed. Consequently LISP implements run time type
A Brief Overview
LISP is characterized by the following ideas (McCarthy):
1. Computing with symbolic expressions rather than
2. Representation of symbolic expressions and other
information by list structure in computer memory.
3. Representation of information on paper, from keyboards
and in other external media mostly by multi-level lists and
sometimes by S-expressions. It has been important that
any kind of data can be represented by single general type.
4. A small set of selector and constructor operations
expressed as functions, i.e. car, cdr and cons.
A Brief Overview (Continued)
5. Composition of functions as a tool for forming more
complex functions.
6. The use of conditional expressions for getting branching
into function definitions.
7. The recursive use of conditional expressions as a
sufficient tool for building computable functions.
8. The use of -expressions for naming functions.
9. The storage of information on the property lists of atoms.
A Brief Overview (Continued)
10. The representation of LISP programs as LISP data that can be
manipulated by object programs. This has prevented the separation
between system programmers and application programmers.
Everyone can “improve” his LISP, and many of these improvements
have developed into “improvements” to the language.
11. The conditional expression interpretation of Boolean connectives.
12. The LISP function eval that serves both as a formal definition of the
language and as an interpreter.
13. Garbage collection as the means of erasure.
14. Minimal requirements for declarations so that LISP statements can be
executed in an on-line environment without preliminaries.
15. LISP statements as a command language in an on-line environment.
Coding Semantic Networks with Lisp
• Suppose that we would like to develop code which will
allow us to reason about elecrical connectivity and
part/subpart relationships within this diagram.
• We will use triples for part_of and connected_to relations
and further specify if the relation is transitive and/or
Semantic Networks - Example
Semantic Networks - Example
(setq known_facts
‘( ( part-of ignition-system ground)
(part-of ignition-system battery)
(part-of ignition-system ignition-switch)
(part-of ignition-system coil)
(part-of ignition-system distributor)
(part-of battery positive-pin)
(part-of battery negative-pin)
(part-of coil output-terminal)
(part-of coil primary-winding)
(part-of coil secondary-winding)
(part-of distributor breaker-points)
(part-of disributor rotor)
(part-of distributor lead)
(number-of lead 4)
(number-of spark-plug 4)
(connected-to ignition-switch positive-pin)
(connected-to primary winding ignition-switch)
(connected-to negative-pin ground)
(connected-to ground breaker-points)
(connected-to ground spark-plug)
(connected-to primary-winding secondary-winding)
(connected-to primary winding output-terminal)
(connected-to output-terminal breaker-points)
(connected-to secondary-winding rotor)
(connected-to rotor lead)
(connected-to lead spark-pluug)
(transitive connected-to)
(transitive part-of)
(commutative connected-to) ) )
Semantic Networks - Example
What sort of questions would we like to answer using this knowledge base?
(connected-to rotor ground)
;; Is the rotor connected to ground?
(and (connected-to positive-pin ground)
(connected-to negative-pin ground)
(or (part-of distributor positive-pin)
(part-of distributor negative-pin) ) )
;; Are both the positive pin and the negative
;; pin connected to ground and is either of them
;; part of the distributor?
Semantic Networks - Example
(find ‘(and (connected-to rotor ground))
;; Is the rotor connected to ground?
(find ‘(and
(connected-to positive-pin ground)
(connected-to negative-pin ground)
(or (part-of distributor positive-pin)
(part-of distributor negative-pin) ) )
;; Are both the positive pin and the negative
;; pin connected to ground and is either of them
;; part of the distributor?
Coding Semantic Networks
Initialization function modifies the fact base by adding the inverse of all commutative
(defun initialization ( )
(let (commut-facts (matcher ‘(commutative *) known-facts)))
(setq known-facts
(append known-facts ;;merges known-facts with the inverse list
(apply ‘append
;;creates the list of inverse facts for commutative facts
‘(lambda (itm) ;;itm comes from commut-facts
;; (‘commutative connected-to’)
(commut (matcher (list (cadr itm) ‘* ‘* ) known-facts ) ) )
;;matcher is called with (‘connected to’ * *) and
commut-facts)))) ) )
Coding Semantic Networks
On the top most level is the find function. It checks for a prefixed and or or then
mapcar’s eval clause across the relationships.
(defun find (p-list )
(cond ((null p-list) t)
((equal (car p-list) ‘and)
(and-lst (mapcar ‘eval-clause
(cdr p-list)
(dupl nil (length (cdr p-list) ) ) ) ) )
((equal (car p-list ) ‘or)
(or-lst (mapcar ‘eval-clause
(cdr p-list)
(dupl nil (length (cdr p-list) ) ) ) ) )
((atom (car p-list))
(printc “error: bad list”)
nil )
(t (and-lst (mapcar ‘eval-claus p-list (dupl nil (length p-list)))) )) )
Coding Semantic Networks
commut function interchanges the attributes within commutative
(defun commut (lst )
(mapcar ‘(lambda (itm) ;;itm comes from lst
(list (car itm) (caddr itm) (cadr itm)) )
lst) )
Coding Semantic Networks
The matcher function retrieves all facts that match the given pattern.
(defun matcher (pat f-list)
(apply ‘append
(mapcar ‘(lambda (item)
(cond ( (match-fact pat item)
(list item) ) ) )
f-list) ) )
The match-fact function compares a single fact with a pattern to see if there is a
(defun match-fact (pat data)
(cond ( (and (null pat) (null data) t)
( (or (null pat) (null data)) nil)
( (or (equal (car pat) ‘* )
(equal (car pat) (car data)) )
(match-fact (cdr pat) (cdr data))) )) )
Coding Semantic Networks
Eval-clause function verifies that each pattern has a match in the database of
known facts. Because embedded ands and ors can occur, it must check for
these embedded clauses and recursively evaluate them. If a pattern is not
directly found in the database, the relation is checked if transitive. Should the
relation be transitive, the transitive semantics are applied through the call to
depth-list keeps track of all visited nodes as the function performs a depth
first search of transitive relations.
Coding Semantic Networks
(defun eval-clause (clause depth-list)
(cond ( (equal (car clause) ‘and)
(and-lst (mapcar ‘eval-clause
(cdr clause)
(dupl nil (length (cdr clause))))) )
( (equal (car clause) ‘or)
(or-lst (mapcar ‘eval-clause
(cdr clause)
(dupl nil (length (cdr clause))))) )
( (matcher clause known-facts) )
( (and ( matcher (list ‘transitive (car clause) ) known-facts)
(not (member (cadr clause) depth-list) )
(trans-eval-clause clause depth-list) ) )
( t nil) ) )
Coding Semantic Networks
(defun trans-eval-clause (clause depth-list)
(let ( (facts (matcher (list (car clause)
(cadr clause)
known-fatcts) ) )
(or-lst (mapcar ‘eval-clause
(modify facts (caddr clause) )
(dupl (cons (cadr clause) depth-list)
(length facts) ) ) ) ) )
Coding Semantic Networks
The modify function is used by transitive relationships to
construct a new set of patterns that must be examined.
The transitive relation (rel fact-a fact-c) is tried to be proven by
first locating all the facts of the form (rel fact-a fact-b). These
facts are then rewritten by the modify function into the format
(rel fact-b fact-c). lst contains the set of retrieved facts, and itm
contains the fact-c
(defun modify (lst itm)
(mapcar ‘(lambda (lst-itm)
(list (car lst-itm)
(caddr lst-itm) itm))
lst) )
Coding Semantic Networks
The and-lst and or-lst functions take a list of true or false values and apply a logical AND or OR
to them.
(defun and-lst (lst)
(cond ((null lst) t)
((car lst) (and-lst (cdr lst) ) )
( t nil) ) )
(defun or-lst (lst)
(cond ((null lst) t)
((car lst) t)
( t or-lst (cdr lst)) )) )
The final function dupl creates a list containing cnt copies of list.
(defun dupl (lst cnt)
(cond ( ( zerop cnt) nil)
(t (cons lst (dupl lst (1-cnt)))) ) )