Functional Paradigm Attempt One: Almost There.

intint binsearch binsearch((intint a[],a[], int int start, start, int int end, end, int int val) val) { { if if (start (start >= >= end) end) return return -1; -1; if if (a[start] (a[start] == == val) val) return return start; start; if if (a[end] (a[end] == == val) val) return return end; end;

int mid = (start + end) / 2; How do we avoid this int mid = (start + end) / 2; assignment? if if (val (val < < a[mid]) a[mid]) return return binsearchbinsearch(a,(a, start, start, mid,mid, val); val); return return binsearch binsearch(a,(a, mid, mid, end end - - 1, 1, val); val); Rupesh Nasre. }} intint main main()() { { intint a[] a[] == {3,{3, 3, 3, 7, 7, 9, 9, 12, 12, 14, 14, 19, 19, 20, 20, 21,21, 27, 27, 41, 41, 53}; 53}; intint val val = = 41; 41; intint na na = = sizeof sizeof(a)(a) / /sizeof sizeof(*a);(*a); CS3100 Paradigms of Programming printf(“%d\n”,printf(“%d\n”, binsearch binsearch(a,(a, 0, 0, na, na, val)); val)); IIT Madras returnreturn 0; 0; Jul 2014 }}

4

Let's BinarySearch Attempt Two

● Implement a binsearch function in C to search intint binsearch binsearch((intint a[], a[], int int start, start, int int midmid, ,int int end, end, int int val) val) { { if if (start (start >= >= end) end) return return -1; -1; for an element in an input array. if if (a[start] (a[start] == == val)val) return return start; start; if if (a[end] (a[end] == == val) val) return return end; end;

● Constraint: Don' use = operator in binsearch. if if (val (val < < a[mid]) a[mid]) returnreturn binsearch binsearch(a,(a, start, start, (start (start + + mid) mid) / /2 2, , mid,mid, val); val); Use the trick again. intint binsearch binsearch(...)(...) { { return return binsearch binsearch(a,(a, mid, mid, (mid (mid + + end) end) / /2 2, ,end, end, val); val); ... } No assignments in ... } binsearch now. }} intint main main()() { { intint main main()() { { intint a[] a[] == {3, {3, 3, 3, 7, 7, 9, 9, 12, 12, 14, 14, 19, 19, 20, 20, 21, 21, 27,27, 41, 41, 53}; 53}; intint a[] a[] = = {3, {3, 3, 3, 7, 7, 9, 9, 12, 12, 14,14, 19, 19, 20, 20, 21, 21, 27, 27, 41,41, 53}; 53}; intint val val = = 41; 41; intint val val = = 41; 41; intint na na = = sizeof sizeof(a)(a) / /sizeof sizeof(*a);(*a); Returns index of the printf(“%d\n”,printf(“%d\n”, binsearch binsearch(a,(a, val)); val)); element if present, -1 printf(“%d\n”,printf(“%d\n”, binsearch binsearch(a,(a, 0, 0, na na / /2 2, ,na, na, val)); val)); otherwise. returnreturn 0; 0; returnreturn 0; 0; }} }}

2 5

Let's BinarySearch On Purity

● How can we avoid assignment? ● Functional programs where side-effects are – Apply your tricks. disallowed are Pure Functional Programs. ● We can use parameter passing to simulate ● Most languages today are impure – but they assignment. support writing PFP. – Use function arguments and return values. ● Functional programs are value-based, not location-based. Therefore, most of them do not support explicit deallocation. – giving a name to a value versus storing a value into a memory location. ● For the same input, the output of a PFP is the 3 same. 6

But Assignments are Necessary! Syntax

● For what? ● (print “Hello World”) – Reuse. – Then, re-compute the value, don't assign. But these multiple xx == f(y);f(y); evaluations must ifif (x(x << 10)10) {{ ifif (f(y)(f(y) << 10)10) {{ be costly. g(x);g(x); g(f(y));g(f(y)); } else { }} else else {{ } else { ● Then don't evaluate h(xh(x ++ 1);1); h(f(y)h(f(y) + + 1);1); them – yet. }} }} ● Use memoisation.

7 10

Lisp Once we have a common language...

● (+ 2 3) ● McCarthy 1958. ● (if (= 1 1) 2 3) ● List Processing language. ● (if (= 1 2) 2 3) ● “the most intelligent way to misuse a computer” ● (list 1 2 3 4 5) ● There are multiple dialects of Lisp today. ● – I use (ANSI Standard). (car '(1 2 3 4 5)) – OO, functional, general-purpose. ● (cdr '(1 2 3 4 5)) – Open source, available on Linux / Mac / Windows. ● (cons 1 '(2 3 4 5)) – For assignments, let's ask TAs. ● (cons '(1) '(2 3 4 5))

● Lost In Stupid Parentheses 8 (append '(2 3) '(4 5 6)) Lots of Irritating Superfluous Parentheses11

Syntax But how do I come out? [23]> quit rupesh@pace$ clisp *** - SYSTEM::READ-EVAL-PRINT: variable QUIT has no value The following restarts are available: ... USE-VALUE :R1 Input a value to be used instead of QUIT. STORE-VALUE :R2 Input a new value for QUIT. [1]> hello Commands can be interpreted. ABORT :R3 Abort main loop Break 1 [24]> exit *** - SYSTEM::READ-EVAL-PRINT: variable HELLO has no value The following restarts are available: *** - SYSTEM::READ-EVAL-PRINT: variable EXIT has no value USE-VALUE :R1 Input a value to be used instead of HELLO. cAse-iNsenSitiVE The following restarts are available: STORE-VALUE :R2 Input a new value for HELLO. USE-VALUE :R1 Input a value to be used instead of EXIT. ABORT :R3 Abort debug loop STORE-VALUE :R2 Input a new value for EXIT. ABORT :R4 Abort debug loop ABORT :R3 Abort debug loop ABORT :R5 Abort debug loop ABORT :R4 Abort main loop ABORT :R6 Abort debug loop Break 2 [25]> Ctrl-C ABORT :R7 Abort debug loop *** - Ctrl-C: User break ABORT :R8 Abort main loop The following restarts are available: Break 1 [2]> (hello) Doesn't help. Considers it as a command. ABORT :R1 Abort debug loop [3]> 'hello Boss, this is not a command, this is data. ABORT :R2 Abort debug loop ABORT :R3 Abort main loop HELLO 9 Break 3 [26]> (quit) (exit) and Ctrl-D also work. 12 [4]> rupesh@pace$

Assignments List Manipulation

● Setq {var value}* Three primitives and one constant ● – (setq x (+ 3 2 1) y (cons x nil)) Available globally. get head of list: car ● get rest of list: cdr ● Let binding ● add an element to a list: cons – (let ((x 10) (y 20)) (+ x y)) Available locally. ● null list: nil or () – (let ((x 10) (y x)) (+ x y)) Error: Parallel assignment – (let* ((x 10) (y x)) (+ x y)) Okay: Sequential assignment Add equality (= or eq) and recursion, and this becomes a universal model of computation.

13 16

Homework Examples Evaluation Rules

1.Given a (list 6 2 3 8 9), find the minimum (there ● A number evaluates to itself. is already a min function available, but can you ● An atom evaluates to its current binding. implement yours?). Use operator <. – More about this later. 2.How to run my saved lisp program in prog.lisp ● A list is a computation without entering the ? Use operator <. – Its first element must evaluate to an operation 3.Implement a binary search tree with insert, – The remaining elements are actual parameters remove and search operations. Use operator <. – The result is the application of the operation to the evaluated actuals.

ButBut ifif eacheach listlist isis aa computation,computation, howhow dodo wewe distinguishdistinguish data?data? 14 17

Uniformity in Code and Data Quote

● Error if operator is undefined ● Expressions are atoms or lists – (1 2 3 4) ● Atoms are numeric or symbols => error ● Lists nest, to form trees ● Quote identifies data ● A program is a list. – (quote (1 2 3 4)) ((defundefun factfact (N)(N) => (1 2 3 4) (if (<= N 1) 1 (if (<= N 1) 1 – (quote (this is data and not a command)) (*(* (fact(-(fact(- NN 1))1)) N)N) )) => (THIS IS DATA AND NOT A COMMAND) )) – '(single quote also works)

15 => (SINGLE QUOTE ALSO WORKS) 18

List Decomposition Control Structures

(defun(defun retfour()retfour() – (car '(this is a list of symbols)) ● Conditional (print(print “I“I amam inin four”)four”) => this atom – (if condition ifblock elseblock)44 )) – (cdr '(this is a list of symbols)) ● General ((defundefun ifelse(n)ifelse(n) => (is a list of symbols) list (cond(cond – (cond (if(if (=(= nn 0)0) (print(print “zero”))“zero”)) – (cdr '(this that)) (pred1 handler1) (if(if (=(= nn 3)3) (print(print “three”))“three”)) (if(if (=(= nn 1)1) (print(print “one”))“one”)) => (that) (pred2 handler2) (if(if (=(= nn (retfour))(retfour)) (print(print “four”))“four”)) – (cdr '(singleton)) ... (if(if (=(= nn 5)5) (print(print “five”))“five”)) ) )) => nil ; empty list )) – (car nil) (cdr nil) (ifelse(ifelse 5)5)

19 22

List Building Control Structures

(defun(defun retfour()retfour() – (cons 'sahib '(biwi aur ghulam)) ● Conditional (print(print “I“I amam inin four”)four”) => (sahib biwi aur ghulam) 44 – (if condition ifblock elseblock) Error )) – (cons 'element-to-list ()) ● General ((defundefun ifelse(n)ifelse(n) => (element-to-list) (cond(cond – (cond (if(if (=(= nn 0)0) ((print((print “zero”)(print“zero”)(print – (cons 'a (cons 'b (cons 'c (cons 'd (cons 'e ()))))) (pred1 handler1) “after“after zero”)))zero”))) (if(if (=(= nn 3)3) (print(print “three”))“three”)) => (a b c d e) (pred2 handler2) (if(if (=(= nn 1)1) (print(print “one”))“one”)) – (list a b c d e) ... (if(if (=(= nn (retfour))(retfour)) (print(print “four”))“four”)) ) (if(if (=(= nn 5)5) (print(print “five”))“five”)) => error )) – (list 'a 'b 'c 'd 'e) )) (ifelse(ifelse 0)0) => (a b c d e) 20 23

Control Structures Control Structures

(defun retfour() ● ● (defun retfour() Conditional Conditional (print(print “I“I amam inin four”)four”) – (if condition ifblock elseblock) – (if condition ifblock elseblock)44 )) ● General ● General ((defundefun ifelse(n)ifelse(n) ((defundefun ifelse(n)ifelse(n) (cond(cond (cond(cond – (cond – (cond (if(if (=(= nn 0)0) ((prognprogn (print(print “zero”)“zero”) (if(if (=(= nn 0)0) (print(print “zero”))“zero”)) (print(print “after“after zero”)))zero”))) (pred1 handler1) (if(if (=(= nn 3)3) (print(print “three”))“three”)) (pred1 handler1) (if(if (=(= nn 3)3) (print(print “three”))“three”)) (pred2 handler2) (if(if (=(= nn 1)1) (print(print “one”))“one”)) (pred2 handler2) (if(if (=(= nn 1)1) (print(print “one”))“one”)) (if(if (=(= nn 4)4) (print(print “four”))“four”)) ...... (if(if (=(= nn (retfour))(retfour)) (print(print “four”))“four”)) (if(if (=(= nn 5)5) (print(print “five”))“five”)) (if(if (=(= nn 5)5) (print(print “five”))“five”)) ) )) ) )) )) )) (ifelse(ifelse 0)0) (ifelse(ifelse 0)0) 21 24 If may be replaceable with when or unless.

Control Structures and then... Recursion

● Conditional ● (defun addone(x) (+ x 1)) – (if condition ifblock elseblock) ● (defun subone(x) (- x 1))

● General ● (defun add(x y) – (cond (if (= y 0) (x) (setq x 'b) (pred1 handler1) (setq x 'b) (case(case xx (add(addone(x) subone(y))))) (pred2 handler2) (a 1) (a 1) ● ... ((d((d e)e) 4)4) (add 10 20) ((b f h d) 3) ) ((b f h d) 3) (b(b 2)2) ● Case (otherwise(otherwise 9)9) )) – Only equality 25 28

Classwork Full Attendance so far

● Write a function tpooh(n) which repeatedly ● Naveen Kumar Reddy does the following ● Harendra Prasad – If n is 1, the function terminates ● M Prathyusha – Else if n is even, it halves n ● Mohana Prasad – Else it sets n to 3n+1 ● J P Sagar ● Assume that a function evenp(n) is given. ● T Swetha ● Homework: Prove that tpooh(n) always terminates for n > 0. ● Vidhya Ramaswamy

26 29

Function Declarations Notes

● (defun double(x) (* x 2)) ● Interoperability of code and data – Does not evaluate the function body – List is the major data structure. – It produces a binding of symbol double with the – Source code is written as lists. function body – Called as homoiconicity. – Defun cannot be used for value binding ● Car: contents of the address part of the – (defun x '5) results in an error memory register ● Cdr: contents of the decrement part of the memory register

27 30

● Multiply each list element by 2 (defun(defun double(x)double(x) (*(* xx 2))2)) (defun(defun double-list(L)double-list(L) First-class Functions (if(if (null(null L)L) nilnil (cons(cons double(firstdouble(first L))L)) (double-list(rest(double-list(rest L)))L))) ● A function does not have a restriction on its )) )) usage. – It can appear anywhere in the program where a number can. ● Reverse list elements

(defun(defun reverse-list(L)reverse-list(L) (if(if (null(null L)L) nilnil (cons(cons reverse(firstreverse(first L))L)) (reverse-list(rest(reverse-list(rest L)))L))) )) ))

31 34

Similar Function Structures Higher Order Functions

● Apply a function on each element of a list. ● A function can take other functions as arguments – Return a list with modified elements. or return them as results. – mapcar – An example we study is differential or integral operator, df/dx. – Maps (as we saw earlier) are examples of higher order (defun(defun mrev(L)mrev(L) functions. (mapcar(mapcar reverse(L))reverse(L)) Error ● HOFs enable partial application or currying, which allows a function to be applied to its arguments one at a time, with each application returning a new function that accepts the next argument.

32 – Recall cout << a << b << c << endl; 35

Similar Function Structures Folds and Unfolds

● Apply a function on each element of a list. ● Folding is a method of applying an operator – Return a list with modified elements. repeatedly over an initial structure to result in a final value. – mapcar – fold + (list 1 2 3 4 5) returns 15. – right fold versus left fold. (defun(defun mrev(L)mrev(L) – (mapcar(mapcar 'reverse(L))'reverse(L)) Contrast with right/left associativity. – Some languages call it reduce (e.g. Lisp, Python). (defun(defun mdouble(L)mdouble(L) – C++ has an std::accumulate function for folds. (mapcar(mapcar 'double(L))'double(L)) ● Unfolding is opposite: it starts from a seed value and builds up a structure by applying an 33 operator. 36

Folds and Unfolds Map using Fold

● For any g such that ● Map f = foldright (cons f) – (g nil) = v and 1.Apply f over the first element – (g cons(first, rest)) = (f first) (g rest) 2.cons it with nil, this gives a non-empty list ● Then, g can be expressed using a fold 3.Apply f over the next element – g = (foldright f v) 4.Cons it with the current list 5.... ● Reduction in parallel.

37 40

Folds and Unfolds Pure Functions

● Unfold builds a structure from an initial value. ● No side effects, same output for the same input irrespective of how many times you call ● Common Lisp does not have a direct unfold (unlike Scheme), ... the function. – Constrast with modifying globals / statics. ● But an unfold can be simulated using loop-collect. ● Caching optimization or memoization – (loop for x from 1 to 10 collect (* x x)) ● Parallelize, thread-safety. ● In general, it can be defined as (unfold p f g seed) to mean ● Recent gcc implementations support pure – (loop for x = seed then (g x) until (p x) collect (f x)) keyword. – (loop for x = 1 then y and y = 1 then (+ x y) until (> y 100) collect y) 38 41

Folding Examples Tail Recursion

; Basic usage ● In general, recursion is costly. > (reduce #'* '(1 2 3 4 5)) 120 – Setup stack / activation record, push parameters, ; Using an initial value > (reduce #'+ '(1 2 3 4 5) :initial-value 100) pop return values, etc. 115 ● A special form of recursion can be efficiently ; Using only a subsequence > (reduce #'+ '(1 2 3 4 5) :start 1 :end 4) implemented: Tail recursion. 9 ; Apply a function to each element first ● If the last function operation is a recursive call, > (reduce #'+ '((a 1) (b 2) (c 3)) :key #'cadr) the call may overwrite the current stack frame. 6 ; Right-associative reduction – Last operation, means nothing is live after this. > (reduce #'expt '(2 3 4) :from-end T) 2417851639229258349412352 – Tail recursion essentially changes to loop ; Compare with semantics, hence faster. > (reduce #'expt '(2 3 4)) 39 42 4096

Tail Recursion Folding on Infinite Lists

● Tail recursion may require defining auxiliary ● foldright, if lazily evaluated, can work with infinite lists (on functions / variables. demand folding) ● foldleft immediately calls itself with new parameters until it reaches the end of the list.

((defundefun facttrfacttr (N(N prod)prod) – This is tail recursion which is good. ((ifif (<=(<= NN 1)1) prodprod – But recurses forever over infinite lists. ((facttr(-((facttr(- NN 1))1)) (*(* prodprod N))N)) ((defundefun factfact (N)(N) ) – Can be avoided by modifying f to look at its second operand. (if (<= N 1) 1 ) (if (<= N 1) 1 )) (*(* (fact(-(fact(- NN 1))1)) N)N) (defun fact (N) ) (defun fact (N) ) facttrfacttr (N(N 1)1) )) ) (fact 10) ) (fact 10) (fact(fact 10)10) 43 46

Classwork Early Termination

● Convert fib(n) to a tail-recursive function. ● When is it not necessary to evaluate an infinite – fib(n) = 1 if n <= 2 list completely? = fib(n-1) + fib(n-2) – Find if the sum of elements is greater than K. – Find if an element greater than K exists in the list. – Find if two infinite lists have the same elements in the same order (state space of two programs) ((defundefun fibfib (N)(N) ((defundefun fibtrfibtr (N(N AA B)B) ((ifif (<=(<= NN 2)2) 11 ((ifif (<=(<= NN 2)2) BB – ... (+(+ fib(-fib(- NN 1)1) fib(-fib(- NN 2)2) (fibtr(fibtr ((-((- NN 1)1) BB (+(+ AA B))B)) ● )) )) Relationship with recursively enumerable )) )) versus Recursive languages.

44 47

Fib in C Safety versus Liveness Property ● Safety property holds across all program intint fibnrfibnr(int(int n)n) {{ 1.83 second ifif (n(n <=<= 2)2) returnreturn 1;1; executions. return fibnr(n-1) + fibnr(n-2); return fibnr(n-1) + fibnr(n-2); – }} x is always zero at this program point. int fibtr(int n, int a, int b) { // tail recursive. 0.00 second int fibtr(int n, int a, int b) { // tail recursive. ● Liveness property holds across at least one ifif (n(n <=<= 2)2) returnreturn b;b; returnreturn fibtr(n-1,fibtr(n-1, b,b, a+b);a+b); program execution. } } – p is null along some path. intint fib(intfib(int n)n) {{ returnreturn fibtr(n,fibtr(n, 1,1, 1);1); ● Absence of a bug is a safety property. //return//return fibnr(n);fibnr(n); }} ● Presence of a bug is a liveness property. intint main()main() {{ printf(“%d\n”,printf(“%d\n”, fib(40);fib(40); ● Proving a liveness property on an infinite list is doable, returnreturn 0;0; but proving its absence may not be possible. }} 45 48

Lambda Value versus Function Binding

>> (boundp (boundp 'foo) 'foo) NIL ● ● NIL Unnamed function template Clisp has two >> (fboundp (fboundp 'foo) 'foo) namespaces: one for NILNIL ● Allows us to return functions >> (setq (setq foo foo 42) 42) values and another for FOOFOO >> foo foo 42 ((defundefun genericadd(funspec) genericadd(funspec) functions. 42 (function (lambda (x) (+ x funspec))) >> (boundp (boundp 'foo) 'foo) (function (lambda (x) (+ x funspec))) T )) T (defun increment(n) >> (fboundp (fboundp 'foo) 'foo) (defun increment(n) NIL ((funcallfuncall (genericadd (genericadd 1) 1) n) n) NIL ) >> (defun (defun foo foo (x) (x) (* (* x x x)) x)) ) FOO ((defundefun decrement(n) decrement(n) FOO (funcall (genericadd -1) n) >> (fboundp (fboundp 'foo) 'foo) (funcall (genericadd -1) n) T )) T (defun double(n) >> foo foo (defun double(n) 42 ((funcallfuncall (genericadd (genericadd n) n) n) n) 42 ) >> (foo (foo 3) 3) ) 9 (increment(increment 9) 9) (decrement (decrement 9) 9) (double (double 9) 9) 9 >> (foo (foo foo)foo) 49 17641764 52

Classwork Function Binding and Lambda

; genericadd defined as before. ● th ● ; genericadd defined as before. Write a function with lambda to return i A lambda could be >> (funcall (funcall (genericadd (genericadd 3) 3) 5) 5) element from a list. stored as a value. 88 >> (apply (apply (genericadd (genericadd 3) 3) '(5)) '(5)) 88 ● ● Then define functions index1(), index3(), Sometimes, it needs >> (defparameter (defparameter *my-fun* *my-fun* (genericadd (genericadd 3)) 3)) to be explicitly converted *MY-FUN**MY-FUN* index100() using the lambda function. >> *my-fun* *my-fun* to a function binding. #{486468C9}> >> (funcall (funcall *my-fun* *my-fun* 5) 5) ● Here, the function 88 >> (*my-fun* (*my-fun* 5) 5) returned by (genericadd Warning:Warning: This This function function is is undefined: undefined: *MY- *MY- 3) is stored in the value- FUN*FUN* cell of *my-fun*.

50 53

eval Function Binding and Lambda

; genericadd defined as before. ● ● A lambda could be stored ; genericadd defined as before. Runtime evaluation of expressions >> (defparameter (defparameter *my-fun* *my-fun* (genericadd (genericadd 3))3)) as a value. *MY-FUN**MY-FUN* (eval '(print “Hello World”)) >> (fboundp (fboundp '*my-fun*) '*my-fun*) ● Symbol-function explicitly NILNIL accesses the function-cell. >> (setf (setf (symbol-function (symbol-function '*my-fun*) '*my-fun*) (genericadd (genericadd 3)) 3)) (eval str) #{4869FA19}> > (fboundp '*my-fun*) ● Thus, we can explicitly set > (fboundp '*my-fun*) ● How to take a type-name from a user and TT a lambda at the function- >> (*my-fun* (*my-fun* 5) 5) create a variable of that type in C? cell of a variable, to make 88 ● How to read a file with valid lisp commands it into a function variable. and execute them at runtime? nd ● If you select 42 entry in a drop-box, how to set variable v42 to true in JavaScript? 51 54

Data Abstraction Binary Tree: Functionality

● Define an interface for a utility. ● Initialization – There is object support in CLisp, which we are not – (defun make-tree-leaf(v) (list v)) interested in. – (defun make-tree-node(v left right) (list v left right)) ● Together the interface functions constitute the ● Predicates abstract data type. – (defun isleaf(n) (= (list-length n) 1)) – (defun isnode(n) (= (list-length n) 3))

55 58

Binary Tree Binary Tree: Client

● Data (make-tree-node '* (make-tree-node '+ – Node (root, leaves, internal) (make-tree-leaf 2) – Value (inside a node) (make-tree-leaf 3)) ● Functionality (make-tree-node '- – Initialization (make-tree-leaf 7) (make-tree-leaf 8))) – Traversal (search) ** – Transformation (mirror) (* (+ (2) (3)) (- (7) (8))) ++ --

22 33 77 88

56 59

Binary Tree: Data Binary Tree: Client ● Each node is represented as a list. (defun tree-search(T val) ● Traversal (defun tree-search(T val) – (list v left right) struct node { val, left, right }; (if(if (tree-leaf (tree-leaf T) T) (equal(equal val val (getval(T)) (getval(T)) – (or (equal val (getval(T)) ● tree-search(T val) (or (equal val (getval(T)) A leaf node may be represented as a singleton list. (tree-search(tree-search (left(T) (left(T) val) val) (tree-search(tree-search (right(T) (right(T) val)))) val)))) – (list v) ● Value could be arbitrary type. – For our example, we will consider symbols in an arithmetic expression. ● A root is simply a node. Classwork: Write a function tree-size for our binary tree to return the number of nodes (+leaves). ● (defun Left(T) (cadr(T)))

57 60

Binary Tree: Client ADT BST

(defun tree-mirror(T) ● (defun tree-mirror(T) ● Transformation (if(if (tree-leaf (tree-leaf T) T) T T BST is a binary tree with additional constraints (make-tree-node(getval(T)(make-tree-node(getval(T) – tree-mirror(T) tree-mirror(right(T))tree-mirror(right(T)) – Left subtree values <= node value tree-mirror(left(T))tree-mirror(left(T)) ))) ))) – Right subtree values > node value ● Interface ** ** – BST-init Classwork: Use Binary Tree + - - + + - - + – BST-isempty(T) interface to implement BST.

2 3 7 8 8 7 3 2 – 2 3 7 8 8 7 3 2 BST-find(T e) Homework: Use Set interface to implement SortedList. Classwork: Write a function tree-pre to return a list of tree values in pre- – BST-insert(T e) order manner. Assume car, cons, append are available. – BST-remove(T e)

If you used append, 61 64 Homework: Write the same function without using append.

ADT Set Implement Lazy Evaluation

● Interface ● Given a list of function-names, each taking – (Make-empty-set) zero arguments and returning an integer, find if any of the functions returns 0. – (set-insert S e) ● – (set-remove S e) Functions should be evaluated lazily. – (set-ismember S e) – Function evaluation and checking return values should interleave. – (set-isempty S) ● Representation – List with unique elements.

62 65

ADT Set 1. Function Composition

(defun(defun make-empty-set()make-empty-set() nil)nil) ● Let's think about pure functions (defun(defun set-insert(Sset-insert(S e)e) adjoinadjoin ee SS :test:test #'equal))#'equal)) (defun(defun set-remove(Sset-remove(S e)e) removeremove ee SS :test:test #'equal))#'equal)) ● You are given f and g functions that map a (defun(defun set-ismember(Sset-ismember(S e)e) membermember ee SS :test:test #'equal))#'equal)) float to float. (defun(defun set-isempty(S)set-isempty(S) (null(null S))S)) – f,g :: Float -> Float ● Now we want to modify their functionality to also return a string. – f',g' :: Float -> (Float, String) Classwork: Implement set-union and set-intersection. x F x F' “f was called”

63 66

1. Function Composition 2. Multivalued Functions

● Now we want to consider composition of f and g. ● Sqrt: computes square root of a real. – Unfortunately, f and g do not produce strings. ● Cbrt: computes cube root.

● So we want to compose f' and g'. ● Consider their implementation for complex – We want the output to contain (f (g x)) and “g was numbers. calledf was called” – Two square roots. – But there is an issue. – Three cube roots. – The output of one cannot be fed as an input to the – Each returns a list of values. other. (f (g x)) x – Sqrt, cbrt :: complex-float -> [complex float] G' F' – These are multivalued functions.

“g was calledf was called”67 70 ++

1. Function Composition 2. Multivalued Functions

● What if there are three functions f, g and h? ● How do we define sixthroot(x)? What is several? – sixthroot(x) = sqrt(cbrt(x)) – We need to do this plumbing for each pair. ● But how do we return all six sixth roots of a ● What if there are different types int, float, etc.? complex number? – The type of each function need to pipeline. – We cannot simply concatenate these functions. ● What if the operations involved are different (in – We need to find cube roots, then for each of them, this case ++)? find the square roots, combine the results into a single list. – We may have to implement it separately for each operator. – In other words, we need bind.

68 71

1. Function Composition 2. Multivalued Functions

● Can we define a higher order function to perform this plumbing for us? ● Bind:: (complex-double -> [complex-double]) ->

● Since output from g' cannot be directly fed as input to ([complex-double] -> [complex-double]) f', we need to upgrade f. ● Bind f x = concat (map f x) ● We define bind for the plumbing. ● Unit x = [x] – Bind :: (float -> (float, string)) -> ((float, string) -> (float, string)) ● Bind applies f' to the correct part of g' x and applies concatenation ++ to the string returned by g' with the string returned by f'.

● An identity function (call it unit) produces empty string. 69 72

3. Random Numbers Monad

● Start from a seed ● In each case we were given a function a -> m b but we need to somehow apply the function to ● Generate a random number an object of type (m a) instead of type a. ● Update the seed (side-effect) ● We do this by defining a function called bind of – Seed needs to be passed and returned. type (a -> m b) -> (m a -> m b), and introducing identity function unit of type a -> m a. ● The triple (m, bind, unit) is a monad.

73 76

3. Random Numbers DSL

● Compose two randomized functions, f and g. ● FP (and weakly typed) languages are often preferred candidates to implement Domain ● The first element of the pair that f returns needs to be passed as a parameter to g. But Specific Languages. the seed returned from g also needs to be ● Specific domains could be: passed in to f. – Thread scheduling algorithms ● The real return value of g needs to be passed – Graph analytics and transformations as the first argument of f. – Distributed computations ● Bind f x seed = let (x', seed') = x seed in f x' – Board game or a set of games seed' – ...

● ● Unit :: a -> (stdgen, stdgen). 74 Today, we will develop a DSL for time units. 77

Pattern TimeDSL Motivation

● (sleep 180) ; sleeps for three minutes ● 1. Function Composition ● – Type FuncCompose a = (a, String) In terms of minutes, we may say – (sleep (* 3 60)) ● 2. Multivalued Variable ● – Type Multivalued a = [a] A time-enthusiast may define a function – (defun sleep-minutes(m) ● 3. Random Numbers (sleep (* m 60))) – Type Randomized a = stdgen -> (a, stdgen) ● Defining a function for each unit of time doesn't seem right. – We should have a way to specify the unit of time

75 along with the value. 78

TimeDSL elsewhere Can we avoid the quote?

● PHP ● I would like to specify ● Javascript – (sleep-units 0.5 h) – ● ... (sleep-units 1 m) – Recall fopen(“filename”, “r”); ● Even date at the command line ● A symbol by default gets evaluated (eager – date '+%s' -> 1412139871 evaluation) – date '+%d' -> 01 ● To avoid evaluation – date '+%d-%m-%Y' -> 01-10-2014 – Use macros ● Not a TimeDSL, but format string of printf can be called a DSL. – Pass by name semantics 79 82

How would you do this in C? SleepUnits-2

#define UNIT_SECONDS 1 (defmacro sleep-units (value unit) `(sleep #define UNIT_MINUTE 2 (* ,value #define UNIT_HOUR 3 ,(case unit FromFrom the the perspective perspective of of a a good good ((s) 1) programmingprogramming practice, practice, these these time time int sleepUnits(int value, int unit) { ((m) 60) unitsunits are are usable usable outside outside sleep-units. sleep-units. switch (value) { ((h) 3600) ((d) 86400) case UNIT_SECONDS: return value; ((ms) 1/1000) case UNIT_MINUTES : return value * 60; ((us) 1/1000000))))) case UNIT_HOUR : return value * 3600; Backquote: It signals that in every expression that follows, each subexpression not preceded by comma is } to be quoted, and each subexpression preceded by Classwork:Classwork: WriteWrite thisthis codecode inin Lisp.Lisp. 80 83 } comma is to be evaluated.

SleepUnits-1 SleepUnits-3

(defun sleep-units (value unit) (defmacro unit-of-time (value unit) (sleep (* value (case unit `(* ,value ,(case unit Classwork:Classwork: Modify Modify this this code code such such that that ((s) 1) h is defined in terms of m. ((s) 1) h is defined in terms of m. ((m) 60) Homework:Homework: Modify Modify thisthis code code suchsuch that that ((m) 60) youyou can can specify specify 2m30s. 2m30s. ((h) 3600) ((h) 3600) ((d) 86400) ((d) 86400) ((ms) 1/1000) ((ms) 1/1000) ((us) 1/1000000)))) ((us) 1/1000000) (defmacro sleep-units (value unit) )))) `(sleep (unit-of-time ,value ,unit))) 81 84 (sleep-units 2 'm) (sleep-units 128 'us) Can we avoid the quote? (sleep-units 3 s) (unit-of-time 1 d)

Unit-of-time Continuations

● Can we generalize it? – For time ● A continuation is a program frozen in action – For distance – ThisThis requires requires defunits defunits to to bebe a a macro, macro, – A single functional object containing the state of a For force which should define unit-of-time, – which should define unit-of-time, computation. ... unit-of-distanceunit-of-distance as as other other macros! macros! ● Can we say something like? – When the object is evaluated, the stored computation – (defunits time s m 60 is restarted where it left off. h 3600 ● ... Scheme has direct support for continuation. ) – Lisp does not have, but it can be programmed. – (defunits distance m km 1000 – We will consider Scheme in our discussion. cm 1/100 ... ) 85 88

defunits definition Continuation in Scheme

● A continuation is a function representing the (defmacro! defunits% (quantity base-unit &rest units) `(defmacro ,(symb 'unit-of- quantity) (,g!val ,g!un) future of a computation. `(* ,,g!val – ,(case ,g!un Whenever an expression is evaluated, something ((,base-unit) 1) is waiting for the value it will return. ,@(mapcar (lambda (x) – `((,(car x)) ,(cadr x))) For the expression (/ (- x 1) 2), when (- x 1) is (group units 2)))))) evaluated, the outer / expression is waiting for the value (and something else is waiting for the outer expression's value) ● It is perceived as a function of one argument. – e.g. (lambda (val) (/ val 2)) Visit letoverlambda.com 86 89

Process State Example

● For expression (/ (- x 1) 2), the continuation when (- x 1) ● Consider processes in sleep mode is evaluated is (lambda (val) (/ val 2)) ● Laptop in hibernation ● For expression ● Highly available applications in industry (define (f1 w) (let ((y (f2 w))) ● Associative or alternating operations (if (integer? y) (list 'a y) 'b))) – Creating pairs out of corresponding nodes of two (define (f2 x) trees. (/ (- x 1) 2)) and f1 is called from the top-level, then when (- x 1) is evaluated, the continuation would be (lambda (val) (let ((y (/ val 2)))

87 (if (integer? y) (list 'a y) 'b))) 90

Continuation in Scheme Lifetime and Context

● A continuation is a function representing the ● Continuations are not used-up once evaluated. future of a computation. ● They can be repeatedly called, like other functions. > (frozen 'thrice) ● It is perceived as a function of one argument. (THE CALL-CC RETURNED THRICE) ● It is a first-class object. > (+ 1 (frozen 'safely)) – We can ask scheme for the current continuation. (THE CALL-CC RETURNED SAFELY) – Scheme will make a one-argument function – For a function call, this would have been an error representing the future of the computation. (1 + list), but since the stack gets ignored (the – We can save this object for as long as we like and stack copy uses list, then append, to the toplevel). when we call it, Scheme would restart the computation that was taking place when the continuation was created. 91 94

Implementation Stack Sharing

● A continuation data structure consists of ● Continuations need not have unique copies of stack. They may share variables with other continuations. – A function (code) > (define froz1) (define froz2) – A copy of the current stack state. > (let ((x 0)) ● Thus, a continuation of time T1 when played (call-with-current-continuation at time T2 would consider local values at T1. (lambda (cc) (set! Froz1 cc) (set! Froz2 cc))) ● Built-in operator call-with-current-continuation (set! X (+ 1 x)) x) 1 > (froz2 ()) 2 > (froz1 ())

92 3 95

Example Nondeterminism

> (define frozen) ● Relies on supernatural foresight. FROZEN > (append '(the call-cc returned) ● Why talk about them when we don't have (list (call-with-current-continuation computers with supernatural powers? (lambda (cc) (set! frozen cc) 'a)))) – They can be simulated by a deterministic (THE CALL-CC RETURNED A) computation. ● Call-cc returns A but stores the state in the global variable frozen. – In pure functional languages, the simulation can > (frozen 'again) be done with backtracking. (THE CALL-CC RETURNED AGAIN)

93 96

Nondeterminism Language How Does choose Work?

● Uses two functions ● Two rules – Choose: It is a function which takes a finite set and 1.It will return a choice for which some future does returns an element. not contain a call to fail. – Fail: It marks the computation invalid. 2.A choose over zero alternatives is equivalent to fail. ● Fail is used to influence the value returned by choose. (let ((x (choose '(1 2)))) The expression as a whole is (if (odd? x) deterministic – it always returns 2. (fail) x))

97 100

Example How Does choose Work?

(let ((x (choose '(1 2 3)))) (let ((x (choose '(1 2)))) (if (odd? x) (if (odd? x)

(+ x 1) Inner choose is deterministic and (let ((y (choose '(a b)))) returns b. Outer choose is x)) nondeterministic and may return (if (eq? y 'a) b or 2. Three outcomes: (fail) ● If choose returns 1, computation returns 2 y)) ● If choose returns 2, computation returns 2 x)) ● If choose returns 3, computation returns 4 As soon as we know what choose returns, we know the future of the computation. 98 101

Choose the Future How Does choose Work?

● In the previous example, we know the future. Classwork: What are the possible values for the following expression? ● In general, each choice is associated with a set of possible futures. – because within some futures, there could be (let ((x (choose '(1 2 3)))) additional chooses. (if (odd? x) (let ((x choose '(2 3)))) This computation has three (choose '()) (if (odd? x) possible futures. x)) (choose '(a b)) x)) 99 102

Dive into the Unknown Iterative Search vs Nondeterministic

● By definition, choose guesses correctly. ● An iterative search is suitable when the state space is bounded. ● Therefore, it is perfectly fine to dive into the unknown – without a fear of failure (unless the – Traversing a state space in an infinite loop would not unknown is full of failure). finish the computation along another path. function Einstein(n) Choose the appropriate ● In contrast, a nondeterministic choice can see mother or father. arbitrarily far into the future. if name(n) == “Einstein” Use fail as a veto to ignore failure paths. – This concept is used in Prolog which can return then return n Our model allows answers one at a time even when the number of else if parents(n) choose to have foresight. answers is infinite. then return Einstein(choose(parents(n))) ● Possible to be implemented using continuations. else fail 103 106

But... The Story So Far...

● Currently, we don't know how to add ● Imperative supernatural powers to computation. ● Object Oriented ● So choose needs to backtrack. ● Functional ● But it is hidden under the hood. ● Next would be Logic ● We say, choose simulates nondeterminism.

104 107

Parlor Trick Logistics

(define (two-numbers) ● Friday class: Question-Answering session. You (list (choose '(0 1 2 3 4 5)) can get your laptop. (choose '(0 1 2 3 4 5)))) ● Monday class: Practice session. Some more

Choose has the ability to problems would be posted. (define (parlor-trick sum) guess hat will happen (let ((nums (two-numbers))) even in the calling ● Q2 on Oct 14 at 08:00 in CS24+CS26. context. (if (= (apply + nums) sum) – Open book, hand-written notes (no printouts, `(the sum of ,@nums) electronics) (fail)))) – CS12B001—CS12B035 in CS24, others in CS26. – You will share desk with MCCS students. > (parlor-trick 7) (THE SUM OF 2 5) 105 108

Acknowledgments

● Edmond Schonberg, NYU ● rosettacode.org ● gnu.org ● Wikipedia

● Philip Fong, SFU

● Dan Piponi (sigfpe.com) ● Doug Hoyte (letoverlambda.com) ● Paul Graham (On Lisp)

109