in Lisp

Dr. Neil T. Dantam

CSCI-561, Colorado School of Mines

Fall 2020

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 1 / 50 Alan Perlis on Programming Languages https://doi.org/10.1145%2F947955.1083808

“A language that doesn’t affect the way you think about programming is not worth knowing.”

Alan J. Perlis (1922-1990) First Turing Award Recipient, 1966

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 2 / 50 Eric Raymond and Paul Graham on Lisp

Lisp is worth learning for a different reason— By induction, the only programmers in a position to see the profound enlightenment experience you will have all the differences in power between the various languages when you finally get it. That experience will make are those who understand the most powerful one. you a better programmer for the rest of your days, (This is probably what Eric Raymond meant about even if you never actually use Lisp itself a lot. Lisp making you a better programmer.) –Eric Raymond –Paul Graham http://www.catb.org/esr/faqs/hacker-howto.html http://www.paulgraham.com/avg.html

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 3 / 50 Peter Siebel on Lisp, “Blub,” and “Omega” https://youtu.be/4NO83wZVT0A?t=18m26s

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 4 / 50 Introduction

Functional Programming Features Outcomes I Persistence: variables and data structures are I Review/understand concepts of immutable (constant) functional programming I Recursion: construct algorithms as recursive I Implement Lisp programs in functions (vs. loops) functional style I First-class functions: can be passed to and returned from other functions

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 5 / 50 Trade-offs of Functional Programming

Pros Cons I Easy (comparatively) to reason about I Different way of thinking about (prove) correctness programs (also a pro!) I Compact (fewer LoC) I Sometimes less (constant-factor) I Immutable structures shared between efficient modules, threads, etc.

Well-aligned with the algorithms and proofs in this course.

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 6 / 50 Outline

Recursion

First-Class Functions

Higher-order Functions

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 7 / 50 Recursion Outline

Recursion

First-Class Functions

Higher-order Functions

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 8 / 50 Recursion Definition: Recursion Review

Definition (Recursion) Example (Factorial) A function or other object defined in terms of itself. ( Base Case: Terminating condition 1 if n = 0 n! = Recursive Case: Reduction towards the base case n ∗ (n − 1)! if n 6= 0

Function fact(n) 1 if 0 = n then return 1 ; 2 else return n ∗ fact(n − 1) ;

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 9 / 50 Recursion Example: Factorial

“Math” ( 1 if n = 0 n! = n ∗ (n − 1)! if n 6= 0

Pseudocode Common Lisp

Procedure fact(x) ( defun f a c t ( n ) 1 if 0 = x then /* Base Case */ ( i f (= n 0) 2 return 1; 1 3 else /* Recursive Case */ (∗ n 4 return x ∗ fact(x − 1); ( f a c t (− n 1 ) ) ) ) )

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 10 / 50 Recursion Exercise: Recursive Fibonacci Sequence

(1, 1, 2, 3, 5, 8, 13, 21, 34, 55,...)  1 if n = 0  fib(n) = 1 if n = 1 fib(n − 1) + fib(n − 2) if n ≥ 2

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 11 / 50 ( defun f i b ( n ) if 0 = n then return 1 ; ( cond ((= n 0) 1) 2 else if 1 = n then return 1 ; ((= n 1) 1) 3 else ( t (+ ( f i b (− n 1) ) 4 return fib(n − 1) + fib(n − 2); ( f i b (− n 2 ) ) ) ) ) )

Recursion Exercise: Recursive Fibonacci Sequence continued

Pseudocode Common Lisp Procedure fib(x)

1

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 12 / 50 Recursion Example: Recursive Accumulate in Lisp

Pseudocode Recursive Accumulate in Lisp

Function accum(S) ( defun accum ( l i s t ) 1 if S then // Recursive Case ( i f l i s t 2 return car(S) + accum (cdr (S)); ;; recursive case 3 else // Base Case (+ ( c a r l i s t ) 4 return 0; ( accum ( cdr l i s t ))) ;; base case 0 ))

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 13 / 50 Recursion Example: Recursive Accumulate Execution Trace

(accumulate ’(1 2 3)) Recursive Accumulate in Lisp

( defun accum ( l i s t ) (+ 1 (accumulate ’(2 3))) ( i f l i s t ;; recursive case (+ 1 (+ 2 (accumulate ’(3)))) (+ ( c a r l i s t ) ( accum ( cdr l i s t ))) ;; base case (+ 1 (+ 2 (+ 3 (accumulate nil)))) 0 ))

(+ 1 (+ 2 (+ 3 0)))

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 14 / 50 Recursion Example: Alternate Recursive Accumulate

Accumulate Alternate Accumulate

( defun accum ( l i s t ) ( defun accum ( l i s t ) ( i f l i s t ( l a b e l s ( ( r e c ( l i s t accum ) ;; recursive case ( i f l i s t (+ ( c a r l i s t ) ;; recursive case ( accum ( cdr l i s t ))) ( r e c ( cdr l i s t ) ;; base case (+ ( c a r l i s t ) 0 )) accum ) ) ;; base case accum ) ) ) ( r e c l i s t 0 ) ) )

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 15 / 50 Recursion Example: Alternate Accumulate Execution Trace

Alternate Accumulate (accumulate ’(1 2 3)) ( defun accum ( l i s t ) ( l a b e l s ( ( r e c ( l i s t accum ) (rec ’(1 2 3) 0) ( i f l i s t ;; recursive case ( r e c ( cdr l i s t ) (rec ’(2 3) 1) (+ ( c a r l i s t ) accum ) ) ;; base case (rec ’(3) 3) accum ) ) ) ( r e c l i s t 0 ) ) ) (rec ’() 6)

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 16 / 50 ( defun r e v e r s e − r e c ( l i s t ) function h(L, r) is ( l a b e l s 2 if L then ( ( h e l p e r ( l i s t r e v e r s e d ) 3 return ( i f l i s t h(cdr(L),cons(car(L), r)); (helper (cdr l i s t ) ( cons ( c a r l i s t ) 4 else return r ; r e v e r s e d ) ) 5 return h(L, NIL); reversed))) ( h e l p e r l i s t n i l ) ) )

Recursion Exercise: Recursive Reverse

reverse (a0 a1 ... an−1 an) (an an−1 ... a1 a0)

Pseudocode Common Lisp Procedure reverse(L)

1

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 17 / 50 Recursion DESTRUCTURING-BIND

DESTRUCTURING-BIND DESTRUCTURING-BIND bind variables to corresponding values draw from a list.

Example Example

(destructuring − b i n d ( a b c ) (destructuring − bind (op e1 e2) ’(1 2 3) ’(+ 1 2) ( l i s t c b a ) ) (+ e1 e2 ) )

Output Output (3 2 1) 3

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 18 / 50 Recursion Example: destructuring-bind Return S-Expression as infix string

Code

( defun a r i t h − s t r i n g ( e ) "Returns −expE as an infix string." ( i f ( l i s t p e ) (destructuring − bind (op e1 e2) e ( format n i l"(~A)~A (~A)" ( a r i t h − s t r i n g e1 ) op ( a r i t h − string e2))) ( format n i l"~A" e)))

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 19 / 50 ( defun e v a l − a r i t h ( e ) ( i f ( l i s t p e ) (destructuring − bind (op e1 e2) e ( cond (( eq op ’+) (+ ( e v a l − a r i t h e1 ) ( e v a l − a r i t h e2 ) ) ) (( eq op ’−) (− ( e v a l − a r i t h e1 ) ( e v a l − arith e2))))) e ) )

Recursion Exercise: destructuring-bind Evaluate Arithmetic S-Expression

Code

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 20 / 50 First-Class Functions Outline

Recursion

First-Class Functions

Higher-order Functions

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 21 / 50 First-Class Functions First-class functions

Definition: First-class functions A has first-class functions when it treats functions like any other variable or object. First-class functions can be: I Bind variables to the function I Passed as arguments to other functions I Returned as the result of other functions

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 22 / 50 First-Class Functions Function Closure Definition (Function Closure) A function closure or lexical closure is a function and an associated set of variable definitions. Etymology: from “closed expression.”

Example (C Function Pointer) Example (Java Class) /∗ D e f i n i t i o n ∗/ // Definition s t r u c t c o n t e x t { class Adder { i n t v a l ; p u b l i c i n t a ; }; public Adder( i n t a_) { a = a_ ; i n t adder ( s t r u c t c o n t e x t ∗cx , i n t x ) { } return cx−>a + x ; p u b l i c i n t c a l l ( i n t x ) { } return x+a ; } /∗ Usage ∗/ } s t r u c t c o n t e x t c ; c . v a l = 1 ; // Usage i n t y = adder(c,2); Adder A = new Adder(1); i n t y = A.call(2); Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 23 / 50 First-Class Functions Closures in Lisp: Local Functions LABELS Defines local functions and executes body using those local functions: (labels ((FUNCTION-NAME VARIABLES FUNCTION-BODY)...) LABELS-BODY)

Example

( l e t ( ( a 1) ) ( l a b e l s ( ( adder ( x ) (+ x a ) ) ) ( adder 2 ) ) )

Output 3

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 24 / 50 First-Class Functions Closures in Lisp: Anonymous Functions LAMBDA FUNCALL Defines an anonymous function: Apply a function to the provided arguments: (lambda VARIABLES FUNCTION-BODY) (funcall FUNCTION ARGUMENTS...)

Example

( l e t ( ( a 1) ) ( f u n c a l l ( lambda ( x ) (+ x a ) ) 2 ))

Output 3

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 25 / 50 First-Class Functions Value and Function Namespaces

Example Value Namespace ( defun foo (x) (+ 1 x)) I Records values I Local: let, let* ( l e t ( ( foo 10)) I Global: defparameter ( p r i n t foo ) ; => 10 ( p r i n t ( foo 1 ) ) ; =>2 ( p r i n t ( foo foo ) ) ) ; => 11

Function Namespace Output I Records function definitions 10 I Local: labels, flet 2 I Global: defun 11

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 26 / 50 First-Class Functions function and funcall FUNCTION FUNCALL Returns the functional value of a name: Apply a function to the provided arguments: (function NAME) The function bound to name (funcall FUNCTION ARGS ...) Return value of FUNCTION Example called on ARGS .... I (function +) Example (#’ +) I I (funcall (lambda (x) I (defun foo (x) (+ 1 x)) (+ 1 x)) #’foo 1) I (labels ((foo (x) (+ 1 x))) 2 #’foo) I (funcall #’+ 1 2) 3

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 27 / 50 Higher-order Functions Outline

Recursion

First-Class Functions

Higher-order Functions

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 28 / 50 Higher-order Functions Higher-order functions

Definition: Higher-order function A function that takes another function as an argument or returns another function as its result.

Example (Passing) Example (Returning) Counterexample

Function f(g,a) Function f(a) Function f(a,b) 1 return g(42, a); 1 function g(b) is 1 return a + b; 2 return a + b;

3 return g;

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 29 / 50 Higher-order Functions Example: Sorting

Example (sorted() in Python)

sorted (["a","ccc","bb"], key= len ) # =>[’a’,’bb’,’ccc’]

Example (qsort() in libc)

void q s o r t ( void ∗ base, size_t nmemb, size_t size , i n t (∗cmp ) ( const void ∗a , const void ∗b ) ) ; void qsort_r ( void ∗ base, size_t nmemb, size_t size , i n t (∗cmp ) ( const void ∗a , const void ∗b , void ∗ cx ) , void ∗ cx ) ;

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 30 / 50 Higher-order Functions Example: Sorting in Lisp

Example (Predicate) Example (Predicate and Key)

( sort ’("a""ccc""bb") ( sort ’("a""ccc""bb") (lambda (a b) #’< : key #’length ) (< ( length a ) ( length b ) ) ) ) ;; =>"a""bb""ccc"

;; =>"a""bb""ccc"

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 31 / 50 ( sort ’(14 63 8 11 51 24 71 89 17 42) #’>)

Higher-order Functions Exercise: Sorting in Lisp

Call SORT to sort the following list in numerically descending order: (14 63 8 11 51 24 71 89 17 42) Sort

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 32 / 50 Higher-order Functions Common Higher-order Functions

map transform elements of a collection fold combine elements of a collection

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 33 / 50 Higher-order Functions Map function

Definition (map) Apply a function to every member of an input sequence, and collect the results into the output sequence.

n n map :( X 7→ Y) × X 7→ Y | {z } |{z} |{z} function input sequence output sequence

Illustration

f output sequence z }| { input sequence MAP   f (x0), f (x1),..., f (xn−1) z }| { x0, x1,..., xn−1

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 34 / 50 Higher-order Functions Example: Map

Increment every element by one λx . x + 1 MAP (1 + 1, 2 + 1, 3 + 1) (2, 3, 4) (1, 2, 3)

Not (¬) every element ¬ MAP (¬>, ¬⊥, ¬>) (⊥, >, ⊥) (>, ⊥, >)

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 35 / 50 Higher-order Functions Algorithm: Map function on lists

Functional Map Imperative Map

Function map(f,s) Procedure map(f,s) 1 if empty(s) then /* s is empty */ 1 n ← length(s); 2 return NIL 2 Y ← make-sequence(n); 3 else /* s has members */ 3 i ← 0; 4 return cons (f (first(s)), map(f , rest(s)); 4 while i < n do 5 Y [i] ← f (s[i]); 6 i ← i + 1;

7 return Y ;

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 36 / 50 Higher-order Functions Example: Map

Example (Illustration) (lambda (x) (+ x 1)) MAP (2 3 4) (1 2 3)

Example (Common Lisp)

(map ’ l i s t ; result type (lambda (x) (+ 1 x)) ; function ( l i s t 1 2 3 ) ) ; sequence ;; RESULT: (23 4)

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 37 / 50 Higher-order Functions Fold-left Definition (fold-left) Apply a binary function to each member of a sequence and the prior result, starting from the left. n fold-left :(Y × X 7→ Y) × Y × X 7→ Y | {z } |{z} |{z} |{z} function init. sequence result

Illustration f f ... y FOLD-LEFT xn f ... (x0, x1, . . ., xn−1) y x0

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 38 / 50 Higher-order Functions Example: Fold-left Example (Addition)

3 + + 1 + 3 0 FOLD-LEFT + 2 6 (1, 2, 3) 0 1

Example (Subtraction)

−3 − − −1 − 3 −6 0 FOLD-LEFT − 2 (1, 2, 3) 0 1

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 39 / 50 Higher-order Functions Algorithm: Fold-left

Functional Imperative

Function fold-left(f, y, X) Procedure fold-left(f, y, X) 1 if empty(X ) then return y; 1 i ← 0; 2 else 2 while i < |X | do 0 3 let y ← f (y, first(X)) in 3 y ← f (y, Xi ); 0 4 return fold-left (f , y , rest(X)); 4 i ← i + 1;

5 return y;

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 40 / 50 Higher-order Functions Example: Fold-left in Lisp

Example (Addition) Example (Subtraction)

( reduce #’+ ( reduce #’− ’(1 2 3) ’(1 2 3) : i n i t i a l − v a l u e 0) : i n i t i a l − v a l u e 0) ;;; => (+ (+ (+0 1) 2) 3) ;;; =>( − (− (− 0 1) 2) 3) ;;; =>6 ;;; => −6

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 41 / 50 Higher-order Functions Example: Fold-Left Accumulate

Pseudocode Lisp

Procedure accum-fold(L) ( defun accum−fold ( l i s t ) 1 function h(a, x) is ( reduce (lambda (accum x) 2 return a + x; (+ x accum ) ) l i s t 3 return fold-left(h, 0, L); : i n i t i a l − v a l u e 0 ))

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 42 / 50 ( defun r e v e r s e − f o l d ( l i s t ) function h(r, x) is ( reduce (lambda (reversed x) 2 return cons(x, r) ; ( cons x reversed)) 3 return fold-left(h, NIL, L); l i s t : i n i t i a l − v a l u e n i l ) )

Higher-order Functions Exercise: Fold-Left Reverse

reverse (a0 a1 ... an−1 an) (an an−1 ... a1 a0)

Pseudocode Common Lisp Procedure reverse(L)

1

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 43 / 50 Higher-order Functions Fold-right Definition (fold-right) Apply a binary function to each member of a sequence and the prior result, starting from the right. n fold-right :(X × Y 7→ Y) × Y × X 7→ Y | {z } |{z} |{z} |{z} function init. sequence result

Illustration f f ... y FOLD-RIGHT x0 ... f (x0, x1, . . ., xn−1) xn−1 y

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 44 / 50 Higher-order Functions Example: Fold-right Example (Addition)

+ + 5

0 FOLD-RIGHT 1 + 3 6 (1, 2, 3) 2 + 3 0

Example (Subtraction)

− − −1

0 FOLD-RIGHT 1 − 3 2 (1, 2, 3) 2 − 3 0

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 45 / 50 Higher-order Functions Algorithm: Fold-right

Recursive Procedural Function fold-right(f,y,X) Procedure fold-right(f,y,X) 1 if empty(X ) then return y; 1 i ← |X | − 1; 2 else 2 while i ≥ 0 do 0 3 let y ← fold-right (f , y, rest(X)) in 3 y ← f (Xi , y) ; 0 4 return f (first(X), y ); 4 i ← i − 1 ;

5 return y;

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 46 / 50 Higher-order Functions Example: Fold-right in Lisp

Example (Addition) Example (Subtraction)

( reduce #’+ ( reduce #’− ’(1 2 3) ’(1 2 3) : i n i t i a l − v a l u e 0 : i n i t i a l − v a l u e 0 : from−end t ) : from−end t ) ;;; => (+1 (+2 (+3 0))) ;;; =>( − 1( − 2( − 3 0))) ;;; =>6 ;;; =>2

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 47 / 50 Higher-order Functions

Application: MapReduce MapReduce: Simplified Data Processing on Large Clusters

User Program Function MapReduce(f,g,X) (1) fork (1) fork (1) fork 1 Y ← parallel-map(f , X ); Master (2) (2) 2 return reduce(g, Y ); assign assign map reduce

worker

split 0 (6) write output (5) remote worker file 0 split 1 (4) local write (5) read I Idea: (3) read split 2 worker I (parallel) map split 3 worker output I (serial) reduce/fold split 4 file 1 worker

I Provides scalability, Input Map Intermediate files Reduce Output fault-tolerance files phasr (on local disks) phase files Fig. 1. Execution overview.

I Implementations: Jeffrey7. When all map Deantasks and reduce and tasks have Sanjaybeen completed, the Ghemawat. mas- Handling Worker Failures ter wakes up the user program. At this point, the MapReduce call The master pings every worker periodically. If no response is received Google MapReduce in the user program returns back to the user code. from a worker in a certain amount of time, the master marks the worker I MapReduce: Simplified Dataas Processingfailed. Any map tasks completed on by the Large worker are reset back to their After successful completion, the output of the mapreduce execution initial idle state and therefore become eligible for scheduling on other I Apache Hadoop is available in the R output files (one per reduce task, with file names workers. Similarly, any map task or reduce task in progress on a failed Clustersspecified by the user).. Typically, Communications users do not need to combine these ofR worker the is also ACM. reset to idle and 2008. becomes eligible for rescheduling. output files into one file; they often pass these files as input to another Completed map tasks are reexecuted on a failure because their out- MapReduce call or use them from another distributed application that put is stored on the local disk(s) of the failed machine and is therefore is able to deal with input that is partitioned into multiple files. inaccessible. Completed reduce tasks do not need to be reexecuted Dantam (Mines CSCI-561) Functional Programming in Lisp since their output is stored in a global fileFall system. 2020 48 / 50 3.2 Master Data Structures When a map task is executed first by worker A and then later exe- The master keeps several data structures. For each map task and cuted by worker B (because A failed), all workers executing reduce reduce task, it stores the state (idle, in-progress, or completed) and the tasks are notified of the reexecution. Any reduce task that has not identity of the worker machine (for nonidle tasks). already read the data from worker A will read the data from worker B. The master is the conduit through which the location of interme- MapReduce is resilient to large-scale worker failures. For example, diate file regions is propagated from map tasks to reduce tasks. There- during one MapReduce operation, network maintenance on a running fore, for each completed map task, the master stores the locations and cluster was causing groups of 80 machines at a time to become unreach- sizes of the R intermediate file regions produced by the map task. able for several minutes. The MapReduce master simply reexecuted the Updates to this location and size information are received as map tasks work done by the unreachable worker machines and continued to make are completed. The information is pushed incrementally to workers forward progress, eventually completing the MapReduce operation. that have in-progress reduce tasks. Semantics in the Presence of Failures 3.3 Fault Tolerance When the user-supplied map and reduce operators are deterministic Since the MapReduce library is designed to help process very large functions of their input values, our distributed implementation pro- amounts of data using hundreds or thousands of machines, the library duces the same output as would have been produced by a nonfaulting must tolerate machine failures gracefully. sequential execution of the entire program.

COMMUNICATIONS OF THE ACM January 2008/Vol. 51, No. 1 109 Higher-order Functions Summary

I Functional Style: I Avoid side-effects (assignment), often recursive I Aligns with inductive proofs I S-Expressions: I Abstract representation of mathematical expressions I Thinking about expression structure, not syntax I Homoiconicity: Maxima TI-89 CAS (Derive CAS) I Same structure for code and data I Process code just like any other data structure I Applications in symbolic reasoning: I Computer Algebra Systems (CAS) Mars Pathfinder planner I (Robot) Planning and Scheduling Learn to think and program functionally and symbolically.

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 49 / 50 Higher-order Functions Dijkstra on Lisp

“LISP has jokingly been described as ‘the most intelligent way to misuse a computer’. I think that description a great compliment because it transmits the full flavour of libera- tion: it has assisted a number of our most gifted fellow humans in thinking previously impossible thoughts.” [emphasis added] https://www.cs.utexas.edu/~EWD/transcriptions/EWD03xx/EWD340.html

Dantam (Mines CSCI-561) Functional Programming in Lisp Fall 2020 50 / 50