0% found this document useful (0 votes)
38 views23 pages

Early in AI Research, There Was A Need For Symbolic Computing

Early AI research utilized functional programming with symbolic computing rather than numbers. Lisp was developed as a functional language using recursion and functions. Lisp began as a purely functional language but later adopted imperative features. Lisp is an interpreted language that evaluates programs dynamically using lists and functions represented as lists. Scheme was developed from Lisp adding static scoping and simplifying the language.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
38 views23 pages

Early in AI Research, There Was A Need For Symbolic Computing

Early AI research utilized functional programming with symbolic computing rather than numbers. Lisp was developed as a functional language using recursion and functions. Lisp began as a purely functional language but later adopted imperative features. Lisp is an interpreted language that evaluates programs dynamically using lists and functions represented as lists. Scheme was developed from Lisp adding static scoping and simplifying the language.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 23

Functional Languages

• Early in AI research, there was a need for symbolic computing


– handling symbols instead of numbers or strings
– parsing input
– recursion
• A functional approach was taken
– programs would comprise functions and function calls, utilizing recursion as
much as possible
– rather than a series of imperative statements with local variables, controlled
through loops
• The earliest functional language was not Lisp, but Lisp was the
successful language to come out of this research
• Some details on Lisp
– Lisp began as a purely functional language although it picked up many
imperative features (loops, go to statements, local vars, etc) from other
languages over time
– Lisp is interpreted (although compilers later became available) leading to the
ability to develop programs in a piecemeal fashion
• eventually, Lisp compilers for better performance
– Lisp initially was dynamically scoped but later Lisp was statically scoped
– Lisp uses only implicit heap dynamic variables
Functional Forms
• A function maps from a domain set to a range set
– the range of these two sets is determined by the function
• A functional form is a higher-order function, that is, a
function that applies to functions
– this can either be a function that accepts a function as a
parameter, or a function that returns a function
• these are important in Lisp as they allow functions to generate new
functions (that is, code that can produce code)
• Construction
– a functional form in which the result of one function is
applied to a second function (nested functions)
• example: f(x) = x + 2, g(x) = 3 * x, h(x) = f o g = f(g(x)) = 3*(x+2)
• Apply to all
– a functional form in which the function is applied to a list of
parameters, returning a list of values
• example: (using f from above) apply(f(2, 5, 12)) = (4, 10, 14)

LISP
A typeless language – we do not declare variables, and variables
are merely pointers that can point to any type of datum
• In early Lisp, there were no local variables, only parameters
• Data Structures are either atoms and lists
– atom – a literal value (char, string, number) usually denoted as ’atom (as in
’a or ’buckeye or ’red)
– list – nil or ( x ) where x is an atom, a series of atoms, or a sub list, or any
combination of these
• example of a list (A (B C D) E F)
• In Lisp, functions are stored in lists and written in prefix notation
– form of a Lisp function is: (function_name param1 param2 …)
– examples:
• (+ 5 7)  returns 12
• (equal? a b) returns T (true) if a = b, nil (false) otherwise
• (/ (+ a b) (- c d)) returns (a + b) / (c – d)
– note the nested parens, this will take some getting used to!
• (cube x)  returns x3
• Functions can also be written as Lambda expressions
– a Lambda expression is an unnamed function in which the parameter(s)
is(are) specified after the function
• e.g. (lambda (x) (* x x)) (5) 25
Representing Lists
Each list node consists of a
data structure (as shown to the The terms CAR and CDR
right) consisting of two pointers, are historical, named after
the CAR points to the item being CDR registers in an early
stored in that node, the CDR machine that ran Lisp
points to the next node
CAR

(A(DEF)BC)

A B C The CDR of a node


can be equal to nil
(equivalent to null or
NULL in Java and C)

C’s & F’s CDRs are nil


D E F
Lisp and the Eval Function
• Lisp’s primary function is EVAL which evaluates a list
or atom at run-time
– functions are special cases of lists: they are lists whose car is
a function name and whose cdr is a list of parameters
• eval will evaluate the function name on the parameters
• that is, (eval lis) does (eval (car lis) (cdr lis))
– this makes Lisp an interpreted language – the eval function is the interpreted
– original Lisp was supposed to be similar to FORTRAN in its appearance,
but this was not practical
• lists are known as s-expressions (symbolic expressions) and can
represent either data or functions
– note that evaluating a list which is not a function will return
an error
• for instance if lis1 is (a b c d) then (eval lis1) would attempt to
evaluate a on (b c d) but a is an atom, not a function!
– to define a function, we use the following notation:
• (function_name (LAMBDA (arg1 … argn) expression))
– where function_name is the name of the function to be called by other
functions and where expression consists of lists of Lisp function calls
Example Math Functions in Lisp
(quote a) or ’a means to take something literally, do
not evaluate it
• 42 returns 42
A without the ’ would be interpreted as a variable,
• ’42 returns 42 but if A has not already been assigned a value, we
• A returns an error get
but ’A returns A an error for trying to access it
• (* 3 7) returns 21 We will use quote to define atoms
• (+ 5 7 8) returns 20 and initialize lists – without using a
quote, the list is evaluated as a
• (- 5 6) returns -1 function call where the first item in
the list is a function name and the
• (- 15 7 2) returns 6 remainder are parameters, but this
• (- 24 (* 4 3)) returns 12 would yield an error because the first
item would not be a function name
• (> 5 6) returns nil (false) but a datum (probably an atom)

• (= 5 (+ 2 3)) returns t (true)


• (* (+ 5 4) (- 8 (/ 6 2)) returns 45
Variables vs. Symbols and Lists
• Variables point to data items which are either symbols
(similar in ways to strings) or lists
– a variable is denoted by its name (e.g., A)
• An atom or list is denoted using a quote mark as in ’A or
’(A B C)
• To create a symbol, use the function QUOTE as in
(QUOTE A) which returns ’A or use the shorthand ’A
– note that ‘ has a different meaning in Lisp to ’ as the ‘ is used
in macro definitions, something we will briefly discuss later
• Notice that ’(+ 3 5) does not return 8, it returns the literal
list (+ 3 5) because ’ says “do not evaluate this”
– we could evaluate this list by doing (eval ’(+ 3 5)) which
would return 8
– so the ’ will allow us to construct a list whether the list stores
data or code, and the eval function will allow us to execute a
list that is code
Scheme
• Lisp was a pioneering programming language in AI and
functional programming, but it had many problems
– the lack of variables led to the programmer having to be tricky
in how to use recursion
– dynamic scoping was also a problem
• Scheme was one of many versions of Lisp that added
functionality to the language
– Scheme emerged from MIT in the mid 70’s
– characterized by a small subset of Lisp features, static scoping
and classes
• Scheme continues to be taught today as an example of a functional
language although Scheme itself has not been used much in AI (AI
tends to use Common Lisp today if it uses any version of Lisp at all)
• We concentrate our examination on Lisp by looking at
Scheme and later Common Lisp rather than Lisp itself
because Lisp is awkward and difficult
Some Functions in Scheme
• CAR – content of address register (returns first item of a list)
• CDR – content of decrement register (returns remainder of list)
• EQ? – equal (for atoms or lists, returns T or nil)
• MEMBER – membership (is a given item in this list?)
• ATOM? – is the datum an atom? (T or nil)
• LIST? – is the datum a list? (T or nil)
• NULL? – is the datum a nil pointer or something? (T or nil)
• EVEN?, ODD?, ZERO? – self explanatory (T or nil)
• =, <>, <, >, <=, >= – self explanatory (T or nil)
• CONS – a list constructor (we’ll go into more detail later)
• LIST – an alternative list constructor (returns a list)
• IF statement: (IF (condition) (then clause) (else clause) )
– returns whatever the then clause or else clause returns
• COND – conditional statement used like a nested if-else structure (we’ll
see more examples of this momentarily)
Assignments in Scheme
• Scheme has 3 different ways of assigning values
– set!, define, let
– (set! a b) is essentially a = b, although in this case, it is a pointer
assignment where a points to b
• if b is a literal, then a points to a memory location storing the value of b,
otherwise a points at the same memory location as what b points to
• (set! a ’(a b c)) creates the list of a, b and c and has the variable a point at the list
• (set! x (+ 6 (- 8 (* 2 1)))) computes the value (6 + (8 – (2 * 1))) or 12, stores it
in memory and has x point at that memory location
• (set! x ’(+ 6 5)) points x at the list (+ 6 5) but not 11
– if we do then do (eval x), we get 11
– (define a b) is used to bind the name a to the item b, this can be used
to bind a constant to its value, or a function name to its code (we do
not use define for variables because the value is not permitted to
change once assigned)
– (let ((a 0) b) –creates local variables for a block enclosed in ( ), in this
case, a is assigned 0, and b has no initial value
Types of Functions
• All functions return a value
– the various mathematical functions return atoms or numerical
values
– predicate functions return T or NIL depending on the outcome
of the condition
• these include EQ?, ATOM?, NULL?, =, <, >, <=, >=, <>, EVEN?,
ODD?, ZERO?
– LIST and CONS are list constructor functions
• they create and return lists
– COND and IF evaluate one or more conditions to select a
function to evaluate and return the value returned by that
function
– SET! is a function with a side effect, it redirects a pointer to
point at the second parameter and then returns the value of the
second parameter
• note that if the second parameter is a literal value (atom or list), there is
another side effect, first storage is allocated to store the literal value
Conditional Examples
• Form is • The IF statement has two forms
– (COND (test1 result1) (test2 – (IF (condition) (function1)) – if
result2) …) the condition returns T, the
– where tests are conditionals and function returns the value returned
results are functions by function1
• The first test to return true – (IF (condition) (function1)
executes the associated (function2)) – if the condition
returns T, the function returns the
function value returned by function1
(cond otherwise it returns the value
((eq? x 0) (set! y 0)) returned by function2
((> x 0) (set! y 1))
(t (set! y –1))) (if (<= hours 40)
(* hours wages)
(cond (+ (* 40 wages)
((<= hours 40) (* hours wages)) (* (* (- hours 40) wages) 1.5)))
(t (+ (* 40 wages)
(* (* (- hours 40) wages) 1.5)))) We might use this as
(set! pay (if …))
CONS – list constructor
• CONS has two parameters and returns the list
constructed by taking the first parameter and making it
the CAR of a list and attaching to it the second
parameter as the CDR
• Since the CDR must be a list, this only works if the
second parameter was already a list
– Examples:
– (CONS ’A ’( ) ) returns (A)
– (CONS ’A ’(B C)) returns (A B C) A
– (CONS ’(A) ’(B)) returns ((A) B)
– (CONS ’(A B) ’(C D)) returns ((A B) C D)
– (CONS ’A ’((B C))) returns (A (B C)) C D

A B
Defining Functions in Scheme
• Form: (DEFINE (funct_name params) body)
– (DEFINE (square num) (* num num))
• so we can now use square as (square x) which returns x 2
– (DEFINE (second alist) (car (cdr alist)))
• notice that for the parameter, I used alist, this was merely to avoid
confusion since list is defined as a function
• if we do (second ’(a b c d)), it returns ’b
– (DEFINE (factorial n)
If n = 0, return 1, otherwise return
(cond ((eq? n 0) 1) n * factorial (n-1)
(T (* n (factorial (- n 1))))))
– (DEFINE (fib n)
(if (> n 2) (+ (fib (- n 1)) (fib (- n 2))) 1))
– (DEFINE (foo alist)
(cond ((null? alist) 0) What does this function do?
(T (+ (foo (cdr alist)) 1))))
More Scheme Functions
(DEFINE (factorial n)
(IF (= n 0) 1 (* n (factorial (- n 1)))))
Member will return T if the atm is found
(DEFINE (member atm lis) in the lis (list) and nil if it is not found
(COND
(member ’d ’(a b c d e f)) returns T
((NULL? lis) NIL)
(member ’d ’(a b e f j k)) returns nil
((EQ? atm (CAR lis)) #T)
(ELSE (member atm (CDR lis))))) Member in Lisp and Common Lisp
will return the list starting at atm and going
to the end of the list, how can we modify
Scheme’s member to do this?
(DEFINE (append lis1 lis2)
(COND ((NULL? lis1) lis2)
(ELSE (CONS (CAR lis1)
(append (CDR lis1) lis2)))))

If we call (append ’(A B) ’(C D E)) we get back (A B C D E)


If we call (append ’((A B) C) ’(D (E F))) we get back
((A B) C D (E F))
Two Similar Scheme Functions
(DEFINE (equalsimp lis1 lis2)
(COND
((NULL? lis1) (NULL? lis2))
((NULL? lis2) NIL)
((EQ? (CAR lis1) (Car lis2))
(equalsimp (CDR lis1) (CDR lis2)))
(ELSE NIL)))

(DEFINE (equal lis1 lis2)


(COND
((ATOM? lis1) (EQ? lis1 lis2))
((ATOM? lis2) NIL)
((equal (CAR lis1) (Car lis2))
(equal (CDR lis1) (CDR lis2)))
(ELSE NIL)))
More Examples
A function that uses local variables to compute quadratic roots
(DEFINE (quadratic_roots a b c)
(LET ((root_part_over_2a (/ (SQRT (- (* b b) (*4 a c))) (* 2 a)))
(minus_b_over_2a (/ (- 0 b) (* 2 a))))
(DISPLAY (+ minus_b_over_2a root_part_over_2a))
(NEWLINE)
(DISPLAY (- minus_b_over_2a root_part_over_2a))))
Two ways to add a list of numbers:
Example of an apply-to-all function (DEFINE (adder lis)
(DEFINE (mapcar fun lis) (COND ((NULL? lis) 0)
(ELSE (+ (CAR lis)
(COND ((NULL? Lis) ( ))
(adder (CDR lis))))))
(ELSE (CONS (fun (CAR lis))
(mapcar fun (CDR lis)))))) (DEFINE (create-adder lis)
(COND ((NULL? Lis) 0)
(mapcar (LAMBDA (X) (* x (+ x 1))) ’(1 5 2 9)) (ELSE (EVAL
returns (2 30 6 90) (CONS ’+ lis)))))

What does this second one do?


Common Lisp
• First developed in 1984
– Incorporates features of many earlier Lisps including Scheme
– Around 1988, CL was combined with CLOS (the Common Lisp
Object System) to be a hybrid OO+functional language (in the
same way that C++ is a combination of C and Smalltalk)
• Common Lisp is similar to C++ in size and complexity
• Common Lisp uses static scoping as its default but allows
for dynamic scoping
• Common Lisp includes
– a full range of built-in data types including arrays, records,
complex #’s, strings, classes
– powerful I/O operations including streams and formatted I/O
– imperative features including a wide variety of control structures
– exception handling (several different forms)
Some Common Lisp Functions
• PROG
– a local block where global variables are unaffected by any statements within
the block
– progn is the same except that the block automatically returns the value of the
last function executed in the local block
• New control statements
– DOTIMES – counter-controlled loop
– DOLIST – iterator loop, executes loop body once for each list item
– DO – general purpose loop, can be counter-controlled or logical, much like
C’s for-loop
• Setf for assignment
– variables declared in let statements initialized to NIL until assigned a value
• DEFUN – defining functions
– form: (DEFUN functionname (params) body)
• body is any single or group of statements, use (let ( ) body) to have local
variables and (progn body) for a block (for instance as the if or else clause of an
if-else statement)
• GO – a goto statement (we will see this next)
• Variations of CAR and CDR: CADR, CDDR, CAAR, CDAR, etc
are all available
Common Lisp Functions
Two member functions Two length functions

Iterative version: Iterative version:

(DEFUN imember (atm lst) (DEFUN ilength (lst)


(PROG ( ) (PROG (sum)
loop_1 (SETQ sum 0)
(COND ((NULL lst) (return nil)) again
((EQUAL atm (CAR lst)) (COND ((NULL lst)
(RETURN T))) (RETURN sum)))
(SETQ lst (CDR lst)) (SETQ sum (+ sum 1))
(GO loop_1))) (SETQ lst (CDR lst))
(GO again)))
Recursive version:
Recursive version:
(DEFUN rmember (atm lst)
(COND ((NULL lst) NIL) (DEFUN rlength (lst)
((EQUAL atm (CAR lst)) T) (COND ((NULL lst) 0)
(T (rmember atm (CDR lst))))) (T (+ 1 (rlength (CDR lst))))))
More Recursive Demonstrations
• The main idea behind Lisp was to use recursion and no
local variables
– while both iteration and local variables (through the let
function are available, we are generally discouraged from
using either as seen in these examples
(defun remove-first (a lis)
(defun member-at-all (a lis)
(cond ((null lis) '( ))
(cond ((null lis) nil)
((equal (car lis) a) (cdr lis))
((listp (car lis))
(t (cons (car lis) (remove-first a (cdr lis))))))
(or (member-at-all a (car lis))
Remove the first instance of the (member-at-all a (cdr lis))))
item a from the list lis ((equal (car lis) a) t)
(t (member-at-all a (cdr lis)))))
(defun all-the-same (lis)
(cond ((null lis) t) The member function looks for a in lis, but
((or (atom lis) (= (length lis) 1)) t) what if a is burried inside of further lists?
((equal (car lis) (cadr lis))
(all-the-same (cdr lis))) member-at-all sees if a is a member at any
(t nil))) level of lis and returns t or nil

Determine if the items in lis are all the same, such as ’(a a a) versus ’(a b a)
Common Lisp Data Structures
• struct – similar to C/C++
– (defstruct car year make model mileage)
– (setf mycar (make-car : year 2005 : model ’camry))
• make-car is automatically generated when use defstruct to define car
• defstruct also creates member accessing functions for each field as car-member
– (car-year mycar) returns 2005
– (car-mileage mycar) returns nil since that member has no value yet
• arrays – use make-array to generate an array
– (setf anarray (make-array ’(10 5)) – creates a 10x5 array and points anarray at it
– access the array using (aref arrayname arrayindex(es))
• as in (setf (aref anarray 3 2) 12) which sets anarray[3][2] = 12
– indices start at 0 as in C/Java
– arrays can be resized/reshaped with the old values retained
• strings – treated as arrays of chars
– can be assigned using make-array or directly as in (setf name “Frank Zappa”)
– accessed through aref and length
• classes – added to the language in the late 80s
– define a class through defclass and a method through defmethod, and an object
(instance) through make-instance
– common lisp classes are unlike other OOPLs because methods are not necessarily
tied to classes, but can be tied to specific objects, and there is no information hiding
mechanisms
• like C++, common lisp classes can have multiple parents
Conclusion
• Functional languages vs. imperative languages:
– variables/memory usage less visible making programming easier
• at least in some situations
– simpler syntactic structures to deal with (everything is a list)
– concurrency easier to design and implement
– interpreted nature makes large systems easier to build
– exploits recursion as much as possible, more so than imperative languages
• Uses of functional languages:
– mostly used in AI research
• Natural Language Understanding (easy parsing partially due to recursive nature)
• Expert Systems (easy rule format)
• Knowledge Representation (symbolic capabilities)
• Machine Learning (dynamic storage)
– used to teach functional programming
– used to implement EMACS, MACSYMA and some operating systems

You might also like