Fall 2016 Images from Sebesta: Copyright © 2012 Addison-Wesley. All rights reserved. The mind is everything. What you think you become. Buddha
"Lisp is worth learning for the profound enlightenment experience you will have when you finally get it; that experience will make you a better programmer for the rest of your days, even if you never actually use Lisp itself a lot.” Eric S. Raymond
1-3 Advantages? Disadvantages? Criteria Readability Writability Reliability Cost Portability Generality Well-definedness
Characteristics Simplicity Few enough features that one can “know” the language A single way to accomplish a single task Data types What data types are available within the language? Syntax design Keywords Blocks Type checking Strong typing / weak typing; implicit typing / explicit typing Aliasing Does the language allow two references to the same memory? 1-4 Advantages? Disadvantages? Criteria Readability Writability Reliability Cost Portability Generality Well-definedness
Copyright © 2012 Addison-Wesley. All rights reserved.1-5 Write a function to check if a string contains only white space
Using state (mutable variables): public static boolean onlyWhitespace (String str) { boolean onlyWhite = true; for(int i = 0; i < str.length(); i++) { if (str.charAt(0)==' '|| str.charAt(0)=='\n'|| str.charAt(0)=='\t') { onlyWhite = false; } return onlyWhite; } 1-6
1-7 Write a function to check if a string contains only white space Write the same function with no mutable variables (no state)
Recursion is that which is recursive. GNU: GNU is not Unix Richard Stallman “The true value of a human being can be found in the degree to which he has attained liberation from the self.” Albert Einstein “The road to enlightenment is long and difficult, and you should try not to forget snacks and magazines.” Anne Lamott, Traveling Mercies: Some Thoughts on Faith
Recursive call is typically split in two pieces: Base Case: stops recursion (does not make a recursive call) Recursive Case: Solves one part of the problem, takes a step towards the base case
Base Case: How can I tell the problem is solved? What is the last step to solve this problem? What small version of this problem can I solve in one step? Recursive Case: How can I take one step, to make the problem smaller? Assume “someone else” is solving the rest of the problem, and you can use “their” solution.
Using state (mutable variables): public static boolean onlyWhitespace (String str) { boolean onlyWhite = true; for(int i = 0; i < str.length(); i++) { if (str.charAt(0)==' '|| str.charAt(0)=='\n'|| str.charAt(0)=='\t') { onlyWhite = false; } return onlyWhite; } No state (No mutable variables): public static boolean onlyWhitespace (String str) { if (str.length <= 0){ return true; } if (str.charAt(0) ==' ' || str.charAt(0) =='\n' || str.charAt(0) =='\t'){ return onlyWhitespace (str.substring(1, str.length()-1); } return false; } 1-11
No state (No mutable variables): public static boolean onlyWhitespace (String str) { if (str.length <= 0){ return true; } if (str.charAt(0) = ' ' || str.charAt(0) = '\n' || str.charAt(0) = '\t'{ return onlyWhitespace (str.substring(1, str.length()-1); } return false; } Actual Functional code (Clojure): (defn onlyWhiteSpace "return true if a string has only white space" [theStr] (if (= theStr "") true (if (or (= (get theStr 0) \space) (= (get theStr 0) \newline) (= (get theStr 0) \tab)) (onlyWhiteSpace (subs theStr 1)) false ) ; end second if ) ; end first if ) ; end onlyWhiteSpace 1-12
Count number of occurrences of the number 7 in a list Base case: Recursive step:
Substitute the number 5 for every 7 in a list Base case: Recursive step:
Write a function that takes a list and returns its reverse Base case: Recursive step:
Write a function that takes a list and returns its reverse Base case: Recursive step: Problem: there is no append for lists in Clojure! How do you add to the end of a list?
Write a function that returns true if the list contains only white space, false otherwise. Base: Recursive step:
Write a function that returns true if the list contains only white space, false otherwise. ( defn onlyWhiteSpace "return true if a string has only white space" [theStr] (if (= theStr "") true (if (or (= (get theStr 0) \space) (= (get theStr 0) \newline) (= (get theStr 0) \tab)) (onlyWhiteSpace (subs theStr 1)) false ) ; end second if ) ; end first if ) ; end onlyWhiteSpace Note the inefficiency
let is a Clojure form to create an environment with bindings What is an environment ? What are bindings ?
Syntax: (let [ (symbol value) (symbol2 value2) … ] (some expression) ) ; end of let
Using local block (defn onlyWhiteSpace2 "return true if a string has only white space" [theStr] (if (= theStr "") true (let [char1 (get theStr 0)] (if (or (= char1 \space) (= char1 \newline) (= char1 \tab)) (onlyWhiteSpace (subs theStr 1)) ; expression if true false ; expression if false ) ; end inner if ) ;end let ) ; end first if ) ; end defn 1-22 Can create local environment with “let” One binding is created: the symbol char1 is bound to the value returned by the call to the function get The one expression in this environment is the if expression get is a built-in function that obtains the character in string theStr at position 0
How do you define multiple local symbols? defn addthree [lst] (let [f (fn [a b c] (+ a b c)) x 5 ] (f (first lst) (first (rest lst)) x) ) ) The first binding is to a function Second binding is x to 5 Note that there is no parenthesis or commas between binding pairs!
Tail recursion Just return from recursive call Do not do any processing on the returned value is the same as a loop So many functional compilers optimize as loop Clojure does not But it does have the recur keyword which optimizes recursion
(defn fib [n] (if (or (= n 1) (= n 0) ) 1 (* n (fib (- n 1))))) Not tail recursion because we must get the return value and modify it
(defn fib_tail [n rslt] (if (or (= n 1) (= n 0)) rslt ; the true expression (fib_tail (- n 1) (* n rslt)) ); end if );end defn tail recursion because we do nothing after the recursive call This is tail recursion BUT we have to change the signature of the function to take 2 parameters. Confuses user
Multiple arity (defn add1 ([x] (+ x 1)) ([x y] (+ x y 1)) ) What does this do? (add1 5) => 6 (add1 5 6) => 12
(defn fib_tail ([n] (fib_tail n 1 )) ([n rslt] (if (or (= n 1) (= n 0)) rslt (fib_tail (- n 1) (* n rslt)) ) ) ) tail recursion because we do nothing after the recursive call
(defn fib_tail ([n] (fib_tail n 1 )) ([n rslt] (if (or (= n 1) (= n 0)) rslt (recur (- n 1) (* n rslt)) ) ) ) This allows Clojure to optimize. recur must be used only in tail recursion*. Actually does processing in parallel *See
Count number of occurrences of the number 7 in a list (defn count7 [lst] (if (empty? lst) 0 (if (= (first lst) 7) (+ 1 (count7 (rest lst))) (count7 (rest lst)) ) ) ) Make this tail recursive!
Implement Selection sort on a list of numbers, breaking the problem down in the following way: Implement findMax and/or findMin functions Implement removeOne function, that can remove a specific value from a list Implement selectionSort function that uses the above functions to sort in ascending order