Presentation is loading. Please wait.

Presentation is loading. Please wait.

Functional Languages Early in AI research, there was a need for symbolic computing handling symbols instead of numbers or strings parsing input recursion.

Similar presentations


Presentation on theme: "Functional Languages Early in AI research, there was a need for symbolic computing handling symbols instead of numbers or strings parsing input recursion."— Presentation transcript:

1 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 We will only study LISP for now, we will return to chapter 15 and other function languages later in the semester Why interpreted? most programmers would build programs in chunks, testing each part out using the interpreter, and then only using the compiler when done Lisp was used extensively for AI research Expert Systems, Natural Language Understanding, Machine Learning, Knowledge Representation, Speech/Vision Understanding, Robotics, Tutorials

2 LISP Purely functional language originally Interpreted
later, picked up many imperative features (loops, go to statements, local vars, etc) Interpreted although compilers later became available leading to the ability to develop programs in a piecemeal fashion Initially dynamically scoped, later statically scoped we explore this later in the semester but basically we much prefer statically scoped variables Uses only implicit heap dynamic variables this means all variables are implicitly allocated and deallocated and are pointers (like Java reference variables, no explicit dereferencing required or allowed) all variables are typeless meaning that a variable can store any type at any time

3 Functional Forms A function maps from a domain set to a range set
the legal values of the 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)

4 LISP Variables In early LISP, there were no local variables, only parameters passed to functions Variables/parameters point at their data, early LISP only had two items that could be pointed to atoms – literal values denoted as ’atom as in ’a or ’buckeye or ’red) don’t confuse these items with strings literal values can also include T (true) and nil (the opposite of T) and a number lists – a linked list storing atoms and sublists, or the value nil lists are embedded in ( ) example lists (A B C D E) (A B C (D E)) (A (B C D) E) ( ) – this is the empty list, or nil The reason early LISP had no local variables was in part to force programmers to use recursion. Without local variables, the only storable values would be global variables and parameters. Most problems can be solved recursively without iteration and with only parameters. NOTE: the apostrophe plays an important role in LISP. The normal apostrophe or left tic mark is used to denote something should be treated literally. This is used to differentiate an atom from a variable, or a list from a function call. Consider the following: (foo a) -- function call to foo passing it variable a (foo ‘a) -- function call to foo passing it the atom a (foo (a b c d)) -- function call to foo passing it the value returned by calling the function a with variables b, c and d (foo ‘(a b c d)) -- function call to foo passing it the list containing the atoms a, b, c and d The values of true and false are t and nil in LISP.

5 LISP Functions All function calls are embedded in ( )
The first item in any function call is the function name, this LISP uses prefix notation function call: (function_name param1 param2 …) examples: (+ 5 7)  returns 12 (cube x)  returns x3 (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! 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

6 Representing Lists CAR CDR A B C D E F ( A ( D E F ) B C )
Each list node consists of a node data structure consisting of two pointers, the CAR points to the item being stored in that node, the CDR points to the next node CAR and CDR are historical, named after registers in an early machine that ran Lisp A B C D E F ( A ( D E F ) 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 The CAR always returns the first item in a list. The CDR always returns a list starting at the first node’s next pointer. For instance, if the list is as shown above, then its car is the atom A and its cdr is the list ((D E F) B C). Starting with this sublist, the car is (D E F) and the cdr is (B C). The car of the sublist (D E F) is the atom D and its cdr is (E F). You cannot take a car or cdr of an atom. The car and cdr of an empty list is nil. The car of a 1-item list is that item as an atom and the cdr is nil.

7 Lisp and the Eval Function
Lisp’s primary function is EVAL which evaluates a list or atom at run-time EVAL when applied to the function calls the function passing it the parameters that make up the rest of the list the EVAL function is what makes LISP interpreted the evaluation is done by taking the cdr of the list and applying it to the car of the list 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

8 Example Math Functions in LISP
42 returns 42 (* 3 7) returns 21 ( ) returns 20 (- 5 6) returns -1 ( ) returns 6 (% 5 3) returns 2 (> 5 6) returns nil (false) (- 24 (* 4 3)) returns 12 (= 5 (+ 2 3)) returns t (true) (* (+ 5 4) (- 8 (/ 6 2)) returns 45 By “returns”, it means if you type in the item, the interpreter uses it as input and applies the eval function on it, returning the item indicated above. The return value can be used by another function, in which case we nest function calls within function calls as seen in the last three examples above. This is where LISP gets tricky since you have to understand prefix notation.

9 Quotes As seen in the last slide, entering 42 returns 42
Similarly, entering ’42 returns 42 What about entering A? if A is a variable with a value, that value is returned, otherwise you get an error Entering ’A returns A (the atom) The quote mark means “use this literally” rather than “evaluate this” imagine we want to define a list, ( ), if we enter this, LISP tries to evaluate this as applying the function 1 to the parameters 2, 3, 4 and 5 and since 1 is not a function, you get an error to define a list, use ’( ) aside from prefix notation, quoting is often one of the most challenging aspects of dealing with LISP

10 Variables vs. Symbols and Lists
Variables point to data items which are either atoms or lists (Common Lisp also has a number of data structures that variables can point to) Unless the atom is a number, T or nil, you must quote it there is a quote function you could use, so instead of ’A, you could use (QUOTE A) – in fact, ’ is just a shortcut for using (QUOTE …) note that LISP also uses the ` (back quote) but for a special purpose dealing with macros, something we won’t cover A list must be quoted unless you are generating it, we look at how to generate lists shortly Note that you can quote a function call as in ’(+ 3 5) this does not return 8, instead it literally returns a list of three atoms, +, 3, 5 we could evaluate this by doing (EVAL ’(+ 3 5)) which would return 8 You might wonder why we want to use ‘(somefunction params) and then use eval on it. In this way, we can build lists that are code – that is, our code can generate new code. In other words, our program can be used to generate program code. This is critical in many AI problems. We will not consider LISP is any more detail. Instead, we will first look at Scheme, a newer and easier LISP dialect and then Common Lisp. CL is the best of the LISP dialects but a very large language. For your first programming assignment, you can use either Scheme or Common Lisp (although all of the resources available to help you will be in CL, not Scheme.

11 Common LISP The textbook covers Scheme, a 1970s dialect of LISP which added all kinds of useful features, and then Common Lisp We concentrate on CL only, skipping Scheme as CL is the better language developed in the 1984 that added classes to make LISP an OOPL not only is CL a better language, but there are a number of Common Lisp interpreters and compilers available, not as many for Scheme CL is roughly equivalent to C++ in terms of power and complexness

12 Common Lisp Incorporates features of many earlier Lisps including Scheme around 1988, CLOS (the Common Lisp Object System) was added to CL creating a hybrid OOP+functional language 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)

13 Some Functions in CL CAR – content of address register
returns first item of a list, this could be a sublist or an atom CDR – content of decrement register returns remainder of list CDR always returns a list or nil if the parameter passed to CDR is the last item in a list EQ – equal used for atoms or pointers returns T or nil EQUAL – equal for atoms or lists, the difference is that EQUAL will compare what two variables are pointing to, much like the difference between x == y and x.equals(y) in Java if A is the list ’(1 2 3) then (EQ A ’(1 2 3)) returns nil while (EQUAL A ’(1 2 3)) returns T

14 More CL Functions MEMBER – membership
is a given item in this list? in LISP and Scheme, this returns T or nil but in CL, it returns the portion of the list starting at the matching item, or nil (MEMBER 3 ’( )) returns the list (3 4) ATOM – is the datum an atom? (T or nil) LISTP – is the datum a list? (T or nil) P stands for “Predicate” meaning T/nil NULL – is the datum a nil pointer or something? (T or nil) EVENP, ODDP, ZEROP – self explanatory (T or nil) =, <>, <, >, <=, >= – self explanatory (T or nil) operates on numbers only Here are some examples. Assume A is 5, B is 6, C is 11, D is ’(A B C) and E is ’(C D) (EVENP A) returns nil (ODDP C) returns T (EVENP (+ A C)) returns T (ATOM B) returns T (LISTP A) returns nil (LISTP D) returns T (MEMBER (CAR E) D) returns T since the (CAR A) is ’C and ’C is in D (EQ (CDR D) E) returns nil

15 More Functions PRINT – to print out the item
assume A points to 5 (PRINT A) outputs 5 (PRINT (+ A 3)) outputs 8 CONS – a list constructor (covered shortly) LIST – an alternative list constructor (returns a list) assume A points to ’apple, B points to ’banana and C points to ’cherry (LIST A B C) returns the list (apple banana cherry) (LIST (LIST A) (LIST B) (LIST C)) returns ((apple) (banana) (cherry)) APPEND – append lists (all params must be lists) (APPEND (LIST A) (LIST B C)) returns (apple banana cherry)

16 Conditional Statements
IF statement has the form (IF (condition) (then clause) (else clause) ) returns whatever the then clause or else clause returns note that if the then or else clause is not a function but just an atom, don’t put it in ( ) example: (if (> A B) (* A B) 0) – returns A * B if A > B and 0 otherwise the else clause is optional COND – conditional statement used like a nested if-else structure (covered shortly)

17 Assignment SETF literally stands for set field
There are there functions, SET, SETQ and SETF basically we want to use SETF for everything because its most flexible, but let’s see why (we will ignore SET) First, the format: (SETQ variable value) value will either be another variable, an atom (quoted), a list (quoted) or the result of a function call (SETQ X 5) (SETQ X ’apple) (SETQ X ’( )) (SETQ X Y) // assumes Y has a value (SETQ (+ A (* B 3)) // assumes A and B have numeric values SETF literally stands for set field assume X is the list ’(1 2 3) (SETQ (CAR X) 5) // error (SETF (CAR X) 5) // changes X to be ’(5 2 3) Both instructions permit multiple assignments as in (setf a 5 b ’apple c T)

18 Types of Functions All functions return a value
mathematical functions return atoms or numerical values predicate functions return T or NIL MEMBER is an exception in that it returns a sublist or NIL LIST and CONS return lists COND and IF return the value of the function executed based on which condition was true SETQ/SETF are functions that return the value being assigned but have a side effect of redirecting the variable’s pointer to point at the second parameter if the second parameter is a literal value (atom or list), there is another side effect in that one or more nodes are dynamically allocated with values inserted appropriately for instance, (SETF X ’(1 2 3)) causes 3 nodes to be allocated with their CAR pointers pointing at storage locations storing 1, 2 and 3, a pointer to the first node is then returned for X to point to

19 The COND Function Basically a nested if-else statement without needing to say “if”, “else”, etc Syntax: (COND ((condition1) (function1)) ((condition2) (function2)) ((condition3) (function3)) ((conditionn) (functionn))) to indicate “else”, the last condition should be T (outside of parens) The first set of code above is equivalent to if(x > 0) return sqrt(x); else if(x == 0) return 1; else return -1; The second set of code is if(hours<=40) return hours * wages; else return (hours – 40 * wages * 1.5; (cond ((> x 0) (sqrt x)) ((= x 0) 1) (t -1)) (cond ((<= hours 40) (* hours wages)) (t (+ (* 40 wages) (* (* (- hours 40) wages) 1.5))))

20 The IF Function The IF statement has two forms
(IF (condition) (function1)) if the condition evaluates to T, the function returns the value returned by function1 otherwise the IF function returns nil (IF (condition) (function1) (function2)) if the condition evaluates to T, the function returns the value returned by function1 otherwise it returns the value returned by function2 (if (<= hours 40) (* hours wages) (+ (* 40 wages) (* (* (- hours 40) wages) 1.5))) We might place the code to the left inside a (setf) as in (setf pay (if (…) (…) (…)))

21 CONS – List Constructor
CONS accepts 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 (or NIL / ’( ) ) examples: (CONS ’A ’( ) ) returns (A) (CONS ’A ’(B C)) returns (A B C) (CONS ’(A) ’(B)) returns ((A) B) (CONS ’(A B) ’(C D)) returns ((A B) C D) (CONS ’A ’((B C))) returns (A (B C)) What do the following CONS statements return? (CONS ’A ’B)  error since the second item must already be a list (CONS ’ (A B) ’(C)  ((A B) C) (CONS ’A (CONS ’B nil))  (CONS ’A ‘(B))  (A B) (CONS ’A (CONS ’(B) (CONS ’C nil)))  (A (B) C) – can you figure out why? We often use CONS when we build a list recursively. We explore this in more detail in the common lisp examples that accompany this lecture. A C D A B

22 Defining Functions Form: (DEFUN name (params) body)
Functions return the last value evaluated in the function, or the last function call (DEFUN square (num) (* num num)) (DEFUN second (alist) (car (cdr alist))) if we do (second ’(a b c d)), it returns ’b (DEFUN factorial (n) (cond ((eq n 0) 1) (T (* n (factorial (- n 1)))))) (DEFUN fib (n) (if (> n 2) (+ (fib (- n 1)) (fib (- n 2))) 1)) (DEFUN foo (alist) (cond ((null alist) 0) (T (+ (foo (cdr alist)) 1)))) If n = 0, return 1, otherwise return n * factorial (n-1) The foo function above computes the length of the list. Here is a recursive function for getting the nth item of a list (assuming the first item is at location 1) (DEFUN NTH (n alist) (if (NULL alist) nil (if (= n 0) (CAR alist) (NTH (- n 1) (CDR alist))))) This function tests alist to see if it is an empty list and if so, returns nil, otherwise if n is 0, it returns the first item of the list (the CAR) otherwise it recursively calls itself with the rest of the list (CDR) and n – 1. There’s actually an (nth) function already defined What does this function do?

23 More CL Functions (DEFUN member (atm lis) (COND ((NULL lis) NIL)
((EQUAL atm (CAR lis)) lis) (T (member atm (CDR lis))))) (DEFUN append (lis1 lis2) (COND ((NULL lis1) lis2) (T (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)) Lets work through the member function to see how it works (member ’c ’(a b c d e))  since lis is not nil, and since the CAR lis, a, does not equal c, we do the else clause and call member with atm and the cdr of lis (b c d e). Again, lis is not nil, its car is not equal to c, so we recursively call member with atm and the cdr of lis, this time (c d e). In this call, lis is not nil but c does equal the car of lis, so we return T. (member ’c ’(a b d e)) would continue to recursively call member with the cdr of lis until lis was nil and therefore member returns nil.

24 Two Similar Functions (DEFUN equalsimp (lis1 lis2) (COND
((NULL lis1) (NULL lis2)) ((NULL lis2) NIL) ((EQ (CAR lis1) (CAR lis2)) (equalsimp (CDR lis1) (CDR lis2))) (T NIL))) (DEFUN equal (lis1 lis2) (COND ((ATOM lis1) (EQ lis1 lis2)) ((ATOM lis2) NIL) ((equal (CAR lis1) (CAR lis2)) (equal (CDR lis1) (CDR lis2))) (T NIL))) How does equalsimp work? We assume we are passing 2 lists to the function (otherwise we will get an error). If the first is nil, then we return whether the second is nil or not (if the first is nil and the second is not, the two are not equal, if they are both nil then they are equal). Otherwise, if the second list is nil, then they are not equal (because the first was not). Otherwise, if the first item of lis1 is equal to the first item of lis2, we recursively call equalsimp with the CDR of both lists. Otherwise, we had a mismatch, return nil. The equalsimp function unfortunately will not work if one or both lists are atoms. So the equal function is superior. If the first item is an atom, it tests to see of the two items are EQ (equal). Two atoms are equal if they are the same atom (.e.g., ’A and ’A or 5 and 5). If one item is a list, then EQ? is nil. If the first item is not an atom and the second is, then we return nil. Otherwise, we have two lists. If the CARs of both lists are equal, then recursively call equal with the CDRs of both lists. Otherwise, return nil. Notice that the third line reads: ((equal (CAR lis1) (CAR lis)) (equal …)) Why do you suppose we tested the CARs of the list with equal instead of EQ? What would happen if we used EQ instead of equal? Consider running the function on the lists (A (B C) D) and (A (B C) D). If we used EQ instead of equal, the function would have returned nil instead of T. Why?

25 Local Variables All of our functions have operated solely on parameters Later dialects of LISP introduced local variables In Common Lisp, define local variables in a (LET) function syntax: (LET (variable list) …) to initialize a variable, use the notation (var value) or (var (functioncall)) anything in … can reference the local variables in the LET function (DEFUN 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)))) (PRINT (+ minus_b_over_2a root_part_over_2a)) (PRINT (- minus_b_over_2a root_part_over_2a))))

26 MAPCAR Recall that in a functional language, we want to be able to pass a function as a parameter and apply that passed function to some list of data MAPCAR does this, returning the computed list MAPCAR is also known as an “apply to all” function (DEFUN mapcar (f lis) (COND ((NULL lis) nil) (T (CONS (f (CAR lis)) (mapcar f (CDR lis)))))) (mapcar #’(LAMBDA (X) (* x (+ x 1))) ’( )) here, f is the function (* x ( + x 1)) and we pass this and the list ( ) to mapcar, getting back the list ( )

27 Other Common Lisp Functions
PROGN allows you to create a block of instructions where global variables are unaffected by any statements in the block also allows you to have multiple instructions where only one function is called for (e.g., the if or else clause) the PROGN function returns the value returned by the last function in the block Loops: DOTIMES – (DOTIMES (var number) … ) (counting loop) DOLIST – (DOLIST (var lis) …) (iterator loop) DO – more complex, see notes section of this page, similar to C’s for loop GO – a goto statement Variations of CAR and CDR: CADR, CDDR, CAAR, CDAR, etc are all available The (DO … ) loop has very complex syntax. Its most basic form is: (do ((var init (stepfunction))) ((terminating condition)) body) Example: (do ((i 0 (+ i 1))) ((= i n)) (print i)) Variations allow you to use multiple loop variables by replacing ((var init (stepfunction))) with ((var1 init1 (step1)) (var2 init2 (step2))…) as in (do ((i 1 (+ i 1)) (j 1 (+ j i))) ((>= j 100)) (print j)) You can also add in the ((terminating condition)) a (function) before the last ) which will cause this function to be called when the terminating condition becomes true. For instance: (do ((i 0 (+ i 1))) ((= i n) (print ‘done)) (print i))

28 Common Lisp Data Structures
struct – similar to C/C++ (defstruct car year make model mileage) (setf mycar (make-car : year 2005 : model ’camry)) (print (car-year mycar)) the functions make-car and car-year are automatically generated when issuing the defstruct to define car (as are all other member accessing functions like car-model) (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 elements using (aref arrayname arrayindex(es)) as in (setf (aref anarray 3 2) 12) which sets anarray[3][2] = 12 arrays can be resized/reshaped with the old values retained

29 Continued 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 there is no information hiding mechanisms like C++, common lisp classes can have multiple parents See the website for more example common lisp code We will return to functional languages later in the semester and examine F# in detail


Download ppt "Functional Languages Early in AI research, there was a need for symbolic computing handling symbols instead of numbers or strings parsing input recursion."

Similar presentations


Ads by Google