Overview
FunctionalFunctional In a functional programming language, functions are first class objects. Programming You can create them, put them in data Programming structures, compose them, specialize them, apply the to arguments, etc. andand LispLisp We’ll look at how functional programming things are done in Lisp
1 UMBC an Honors University in Maryland 2
Concepts and functions eval
Eval Remember: Lisp code is just an s-expression Apply You can call Lisp’s evaluation process with the eval function. Funcall > (setf s1 '(second '(one two three))) Lambda (second '(ONE TWO THREE))
> (eval s1) (cdr (quote (a . b))) TWO (quote (a . b)) > (eval (list 'cdr (car '((quote (a . b)) c)))) B UMBC UMBC an Honors University in Maryland 3 an Honors University in Maryland 4
1 Functions as objects Functions as objects Just as we can use ‘ as an abbreviation for In lisp, functions are regular objects, like Just as we can use ‘ as an abbreviation for symbols, or strings, or lists. quote, we can use #’ as an abbreviation for function: If we give the name of a function to function, function: it will return the associated object. > #’+ Like quote, function is a special operator, so #
Apply Funcall
Apply takes a function and a list of arguments for it, and returns the result of applying the The function funcall is like apply but does function to the arguments: not need the arguments to be packaged in > (apply #’+ ‘(1 2 3)) a list: 6 > (funcall #’+ 1 2 3) It can be given any number of arguments, so 6 long as the last is a list: 6 > (apply #’+ 1 2 ‘(3 4 5)) It could be written as: 15 (defun funcall (f &rest args) A simplified version of apply could be written: (eval (cons f args))) (defun apply (f list) (eval (cons f list))) UMBC UMBC an Honors University in Maryland 7 an Honors University in Maryland 8
2 Lambda Lambda expression
The defun macro creates a function and A lambdalambda expressionexpression is a list containing gives it a name. the symbol lambdalambda, followed by a list of However, functions don’t have to have parameters, followed by a body of zero names, and we don’t need defun to define or more expressions: them. > (setf f (lambda (x) (+ x 1))) We can refer to functions literally by using #
UMBC UMBC an Honors University in Maryland 9 an Honors University in Maryland 10
Lambda expression Recap
A lambda expression can be considered as Two ways to make functions specifying an anonymous function. specifying an anonymous function. (defun foo (x) (+ x 1)) Like an ordinary function name, a lambda Like an ordinary function name, a lambda (setf bar (lambda (x) (+ x 1))) expression can be the first element of a function call: Calling a function > ((lambda (x) (+ x 100)) 1) (foo 100) => 101 ((lambda (x) (+ x 1) 100) => 101 101 ((lambda (x) (+ x 1) 100) => 101 (bar 100) => ??? and by affixing a sharp-quote to a lambda expression, we get the corresponding function: Getting a functional object > (funcall #’(lambda (x) (+ x 100)) 1) (function foo) 101 (function (lambda (x) (+ x 100))) UMBC UMBC an Honors University in Maryland 11 an Honors University in Maryland 12
3 Who cares? Mapcar and friends
What good is this, anyway? Sometimes its useful to apply a function to Having functions as “first class objects” every element of a list and return a list of allows us to do some interesting things. the results. > (mapcar #’1+ ‘(-1 2 -3)) As we will see… (0 3 -2) > (mapcar #’abs (mapcar #’1+ ‘‘(-1 2 -3))) (0 3 2) > (mapcar ‘integerp ‘(a 2 (b) -3 nil 4)) (nil t nil t nil t) UMBC UMBC an Honors University in Maryland 13 an Honors University in Maryland 14
Defining mapcar Mapping functions Mapcar has been generalized to functions which Mapcar is built in but could be defined take more than one argument > (mapcar #’> ‘(5 3 1 0) ‘(4 4 4 -4)) (defun mapcar (f list) (t nil nil t) (cond ((null list) nil) > (mapcar #'cons '(a b c) '(1 2 3)) ((consp list) ((a . 1) (b . 2) (c . 3)) > (mapcar #’list ‘(a b c) ‘(1 2 3 4)) (cons (funcall f (car list)) ((A 1) (B 2) (C 3)) (mapcar f (cdr list)))) > (mapcar #’(lambda (x y) (* (- x 1)(+ y 1))) (t (error “bad arg to mapcar”)))) ‘(1 2 3) ‘(2 3 4)) (0 4 10) UMBC UMBC an Honors University in Maryland 15 an Honors University in Maryland 16
4 Maplist Every and Some every and some take a predicate and one or The related function maplist takes the same arguments, but more sequences calls the function on successive CDRs of the lists: When given just one sequence, they test > (maplist #’(lambda (x) x) ‘(a b c)) whether the elements satisfy the predicate: ((A B C) (B C) (C)) > (every #’oddp ‘(1 3 5)) > (maplist #'(lambda (x) (cons 'foo x)) '(a b c d)) T ((foo a b c d) (foo b c d) (foo c d) (foo d)) > (some #’evenp ‘(1 2 3)) > (maplist #'(lambda (x) (if (member (car x) (cdr x)) 0 1))) T '(a b a c d b c)) If given >1 sequences, the predicate must (0 0 1 0 1 1 1) take as many arguments as there are sequences, and arguments are drawn one at a mapcan, There is also mapcan, . Use the on-line time from them: Common Lisp the Language to discover what these mapping mapc, and mapl > (every #’> ‘(1 3 5) ‘(0 2 4)) functions do. > (every #’> ‘(1 3 5) ‘(0 2 4)) T UMBC UMBC an Honors University in Maryland 17 an Honors University in Maryland 18
Example: filter Example: reduce (defun filter (function list) ;; returns elements of list for which function is true. ¾ Reduce takes (i) a function, (ii) a final value, and (cond ((null list) nil) (iii) a list ((funcall function (car list)) (cons (car list) ¾ Reduce (+ 0 [v1 v2 v3 … vn]) is just (filter (cdr list) function))) V1 + V2 + V3 + … Vn +0 (t (filter function (cdr list))))) ¾ In Lisp notation: filter > (reduce #’+ 0 ‘(1 2 3 4 5)) > (filter #’evenp ‘(1 2 3 4 5 6 7)) (2 4 6) 15 > (filter #’prime (integers 2 20) ) (reduce #’* 1 ‘(1 2 3 4 5)) (2 3 5 7 11 13 17 19) 120 UMBC UMBC an Honors University in Maryland 19 an Honors University in Maryland 20
5 Example: reduce Examples: reduce
(defun reduce (function final list) (defun copylist (list) (if (null list) (reduce #'cons nil list)) final (funcall function (defun appendlist (list) (first list) (reduce #'append nil list)) (reduce function final (rest list))))) (reduce #'append nil list))
(defun sumlist (list) (reduce #'+ 0 list)) > (appendlist ‘((a b)(1 2)(c d)(3 4))) (defun mullist (list) (reduce #'* 1 list)) (a b 1 2 c d 3 4) UMBC UMBC an Honors University in Maryland 21 an Honors University in Maryland 22
Free variables When are functions defined?
Suppose we have a function with a free Most of the time we use defun, we are variable, like increment in this: defining functions “at the top level” (defun huh (x) (+ x increment) So free variables are global variables If we call (huh 100) what should happen? Lisp is lexically scoped, so free variables are But, lambda expressions allow us to define looked up in the environment in which the functions in a local environment function was defined. > (setf increment 1000) => the need for closures 1000 > (huh 100) 1100 UMBC UMBC an Honors University in Maryland 23 an Honors University in Maryland 24
6 Closures Closure example > (defun make-counter ( ) Lisp is a lexically scoped language. (let ((count 0)) Free variables referenced in a function (lambda ( ) (setf count (1+ count))))) those are looked up in the environment in MAKE-COUNTER which the function is defined. > (setf c (make-counter)) #
Closure example 2 Closure example 3
> (setf c1 (make-counter)) > (defun make-counter (&optional (increment 1)) #
7 SO?
Closure are quite powerful, as we will see In effect, they allow you to suspend execution of a thread by creating a function that will resume it And later call the function to resume computation We’ll look at this when we look at streams
UMBC UMBC an Honors University in Maryland 29 an Honors University in Maryland 30
8