LISP John McCarthy and Marvin Minsky formed MIT’s AI Project in 1958. Suggested reading: John...

Post on 02-Jan-2016

215 views 0 download

transcript

LISP

John McCarthy and Marvin Minsky formed MIT’s AI Project in 1958. 

Suggested reading: John McCarthy’s home page http://www-formal.stanford.edu/jmc/

McCarthy developed LISP in 1958 –1959.

Functional Programming

• Imperative languages are based on Von Newman Architecture.Functional programming paradigm is based on mathematical functions.

F(x) = 2x + 5

•Mathematical function is mapping of members of one set, called the domain set, to another set called the range set.

Functional Programming

• Evaluation is controlled by recursion and conditional expressions rather than by sequencing and iterative repetition that are common to imperative languages.

•In mathematical functions there are no variables in the sense of imperative languages, so there can be no side effect.

•Imperative languages refer to values stored in memory locations, so side effects are generated.

Functional Programming

• Naming a function can be separated from defining a function. Lambda notation is devised to define a nameless function.

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

h f g

If f(x) x + 2

g(x) x * 3

Then,

h(x) f(g(x)), or h(x) (3 * x) + 2

Functional Forms

Construction

• Is a functional form that takes a list of functions as parameters and collects the results in a list.

Let f(x) x * x

g(x) x * 3

h(x) x / 2

then,

[f, g, h](4) yields (16, 12, 2)

Functional Forms

Apply-to-all

• Is a functional form that takes a single functions as a parameter and and applies it to a list of arguments.

Let

h(x) x * x

then,

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

The execution of a function always produces the same result when given the same parameters. This is called referential transparency.

A purely functional programming language does not use variables and assignment statements. Without variables iterative constructs are not possible. Repetition must be done by recursion.

Fundamentals of Functional Programming

Although functional languages are often implemented with interpreters, they can also be complied.

Imperative languages may have functional side effects.

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

LISP

• 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 of LISP

• The syntactic elements of the LISP programming language are symbolic expressions.

• Both programs and data are represented as s-expressions. An s-expression may be either an atom or a list.

• Symbolic atoms are composed of letters numbers and certain non-alphanumeric characters (* - + $ % ^ &_ > < )

• A list is a sequence of either atoms or other lists separated by blanks and enclosed in parentheses.

Examples

• (A B C D)

• (A (B C) D (E (F G)))

Concepts behind LISP

• McCarthy thought that the processing of symbolic links is more natural than Turing machines.

• One of the common requirements of the study of computation is that one must be able to prove certain computability characteristics of the whole class of whatever model of computation is being used.

• In the case of Turing machine model one can construct a universal Turing machine that can mimic the operations of any Turing Machine.

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.

Concepts behind LISP

(function_name arg_1 … arg_n)

Example( + 5 7 )

evaluates to 12.

Examples

• (- (+ 3 4) 7)

• (=(+ 2 3) 5)

• (list 1 2 3 4)

• (nth 0(list a b c d)

0

t

(1 2 3 4)

a

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

Definition

S-Expression

 

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

• A list is a non-atomic expression.

• In evaluating an s-expression:

– If the s-expression is a number, return the value of the number.

– If the s-expression is an atomic symbol, return the value bound to that symbol; if it is not bound then it is an error.

– 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 s-expression 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 )) (a b c)

(‘(+ 1 3)) (+ 1 3 )

(3 7)

((+ 1 2) (+ 3 4))

t

Control of LISP Evaluation: quote and eval

eval is a complement to quote.

(quote(+ 2 3)) (+ 2 3)

(eval(quote(+ 2 3))) 5

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

25

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

cond (<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 takes three arguments

(defun absolute-value(x)

(if (< x 0 ) (-x) x ))

Predicates

A predicate is a LISP function that returns nil to indicate ‘false’ and anything other than nil to indicate ‘true’.

> (= 9 (+ 4 5))

t

 

>(oddp 4)

nil

Examples to arithmetic predicates are: <, >, =, oddp, evenp, zerop, plusp, minusp.

>(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)) nil >(or( t nil t t) t

Functions, lists, and Symbolic Computing

 Using nth it is possible to define access functions for the various fields of a data record.

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

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)

new-salary(number-field record)))

>(replace-salary-field ‘(((Ada Lovelance) 45000.00 38519) 50000.00)) ((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 ))

a

>(cdr ‘(a b c))

(b c)

>(car(cdr ’(a b c d)))

b

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.

Example:

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)

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

(1 2 3 4) ((1 2) 3 4)

car-cdr recursion adds one more dimension to simple cdr recursion.

(defun count-atoms (list)

(cond ((null list) 0)

((atom list) 1)

(t (+(count-atoms(car list))

(count-atoms(cdr-list))))))

>(count-atoms ‘((1 2 ) 3 (((4 5 (6)))))

6

Functional Programming

 

(set ‘inc 0)

(defun f(x)

(set ‘inc (+ inc 1))

(+ x inc))

>(f 4)

5

>(f 4)

6

In this example x is a bound variable where inc is a free variable.

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

(x))

The Assignment of Value

setq : The variable is assigned the value of the form.

set: symbol is assigned the value given

setf refers to memory location

(setq x 23) ;x assigned 23

(set a 999): ;arguments are evaluated

setf regards the first argument as naming a memory location.

>(setf x ‘(a b c))

(a b c)

>x

(a b c)

 >(setf(car x) 1)

1

>x

(1 b c)

>(setf(cdr x) ‘(2 3))

(2 3)

>x

(1 2 3)

The Assignment of Value

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

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)

5

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

(1 3 5 6)

>(filter ‘(1 a b c 5 7) ‘numberp)

(1 5 7)

Another important class of higher-order functions consists of mapping functions.

>(mapcar ‘+ ‘(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 functiom in the global environment using a defun even though the function may be used only once.

((lambda (x y) (* x y) (30 40)) 1200

((lambda (x y) (* x y) ()) 20 30) nil

Lambda Expressions

((lambda (&optional x y) (list x y))) (nil nil)

((lambda &optional x y)

(list x y)) 10 20)(10 20)

((lambda &optional (x 0) (y 0))

(list x y)) 10 20)

(10 20)

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

7

>(mapcar ‘(lambda(x) (* x x)) ‘(1 2 3 4 5))

(1 2 9 16 25)

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

>(match ‘(likes bill wine) ‘(likes bill wine))

t

 >(match ‘(likes bill ?) ‘(likes bill wine))

t

 >(match ‘(likes bill ?) ‘(likes ? wine))

t

Homework

Define a LISP function that reverses a given list