clojure 3 recursion, higher-order-functions 27-aug-15

22
Clojure 3 Recursion, Higher-order-functions Dec 31, 2 021

Upload: linda-harrell

Post on 11-Jan-2016

218 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Clojure 3

Recursion, Higher-order-functions

Apr 21, 2023

Page 2: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Running Clojure C:\Users\Dave>cd C:\Programs\clojure-1.2.0

C:\Programs\clojure-1.2.0>java -cp clojure.jar clojure.mainClojure 1.2.0user=> (load-file "E:/Programming/Clojure programs on E/test.clj")#'user/fruituser=>

The response, #'user/fruit, is because “fruit” was the last thing defined on this file

Although jEdit has a clojure mode, I don’t like it Syntax coloring is good, but indentation is strange (buggy?) and agressive The lisp mode doesn’t syntax color as well, but indents properly

Comments: A “doc” string is a string that goes just before the parameter list Other comments start with a semicolon (;) and extend to the end of the line

Page 3: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

3

Functions The syntax to define a named function is:

(defn function_name docstring? [arguments] expressions) The value of the function is the value of the last expression evaluated

The syntax of a function call is(function arguments)

Notice that the function being called is the first thing inside the parentheses This need not be the name of a function; it can be any expression that results in a

function

A Clojure function can be overloaded (have different bodies for different parameter lists)

Syntax:(defn function_name docstring? ([arguments] expressions) . . . ([arguments] expressions) )

Page 4: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Tail recursion A recursive function is one that calls itself A recursive function typically has three parts:

1. One or more base cases that solve the simplest cases of the problem without recurring

2. Recursive calls to solve subproblems that are simpler but of the same type as the given problem

3. Code to augment solutions to subproblems into solutions of the given problem

A function is tail recursive if the recursive call is the very last thing that the function does

In other words, part 3 above is empty—no additional work need be done If the function has multiple exits, it is tail recursive only if every

recursive call returns without doing additional work

Page 5: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Façades

A façade is a function that provides a different (usually better) interface to another function Often this means supplying arguments that are only used

for initialization In Clojure it’s easy to define a function within

another function This allows an “uglier” version of the function to be hidden

Functions can also be overloaded

5

Page 6: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Tail recursion (Erlang)

Non-tail recursive function to find the length of a list:len([]) -> 0;len([_ | T]) -> 1 + len(T).

Tail recursive function to find the length of a list:len(L) -> len(0, L).

len(N, []) -> N;len(N, [_ | T]) -> len(N + 1, T).

Page 7: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Tail recursion (Clojure)

Non-tail recursive function to find the length of a list:(defn len-1 [lst] (if (empty? lst) 0 (inc (len-1 (rest lst))) ) )

Tail recursive function to find the length of a list:(defn len-2 ([lst] (len-2 0 lst)) ([n lst] (if (empty? lst) n (len-2 (inc n) (rest lst)) ) ) )

Page 8: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

recur

The previous function, len-2, is tail-recursive, but the compiler doesn’t optimize it into a loop

Clojure runs on the JVM, which doesn’t optimize tail recursion

Workaround:(defn len-2 ([lst] (len-2 0 lst)) ([n lst] (if (empty? lst) n (recur (inc n) (rest lst))) ) )

Page 9: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Tail recursion (Erlang)

Non-tail recursive function to find the factorial:

factorial(1) -> 1;factorial(N) -> N * factorial(N - 1).

Tail recursive function to find the factorial:

factorial(N) -> factorial(1, N).

factorial(Acc, 1) -> Acc;factorial(Acc, N) -> factorial(N * Acc, N - 1).

Page 10: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Tail recursion (Clojure) Non-tail recursive function to find the factorial:(defn factorial-1 [n] (if (= n 1) 1 (* n (factorial-1 (dec n))) )

Tail recursive function to find the factorial:(defn factorial-2 ([n] (factorial-2 1 n)) ([acc n] (if (= n 1) acc (recur (* n acc) (dec n)) ) ) )

Page 11: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Functions that take functions

Functional programming languages allow you to use a function as a parameter to another function

Almost all functional programming languages provide these three extremely useful functions: map applies a function to every element of a sequence, giving

a sequence of the results filter applies a predicate to every element of a sequence,

giving a sequence of the results reduce (or fold) applies a binary operation “between” each

pair of elements, giving a single (non-sequence) result There are often different versions for left- and right-associative

operations, and for providing or not providing an initial value

11

Page 12: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

map (def fruit '((apple red) (banana yellow) (cherry

red)))

user=> (map first fruit)(apple banana cherry)

(defn my-map [f lst] (if (empty? lst) () (cons (f (first lst)) (my-map f (rest lst))) ) )

user=> (map my-first fruit)(apple banana cherry)

Page 13: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Anonymous functions

An anonymous function has the syntax: (fn [parameters] body)

Example: (fn [x] (* x x))

Anonymous functions are used when The function body is short and simple, and It is only needed in one place

Page 14: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

filter (def fruit '((apple red) (banana yellow) (cherry

red)))

user=> (filter (fn [x] (= (second x) 'red)) fruit)((apple red) (cherry red))

(defn my-filter [p lst] (cond (empty? lst) () (p (first lst)) (cons (first lst) (my-filter p (rest lst))) :else (my-filter p (rest lst)) ) )

user=> (my-filter (fn [x] (= (second x) 'red)) fruit)((apple red) (cherry red))

Page 15: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Speaking of maps…

A map or hash is a sequence of key/value pairs, enclosed in braces, for example,{:ace 1, :deuce 2, "trey" 3}

Elements are separated by whitespace or commas It is helpful to use commas between key/value pairs

A map is also a function: user=> (def cards {:ace 1, :deuce 2, "trey" 3})#'user/cards

user=> (cards :deuce)2

Keywords are also functions: user=> (:deuce cards)2

Page 16: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

reduce user=>

(defn my-reduce [f init lst] (cond (empty? lst) init :else (recur f (f init (first lst)) (rest lst)) ) )#'user/my-reduce

user=> (my-reduce + 0 '(11 22 33))66

user=> (my-reduce * 1 '(2 3 4))24

Page 17: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Functions that return functions

A closure is a function that contains and works with, not only its parameters, but values from the scope in which it was defined

Currying creates a new function with fewer arguments than the original function

Function composition combines two or more functions into a new function

17

Page 18: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Closures I user=> (defn rangechecker [min max]

(fn [num] (and (>= num min) (<= num max))) )#'user/rangechecker

user=> (def in-range? (rangechecker 0 100))#'user/in-range?

user=> (in-range? 75)true

user=> (in-range? 101)false

Page 19: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Closures II user=> (defn adjust-range [min max]

(fn [num] (cond (< num min) min (> num max) max :else num )) )#'user/adjust-range

user=> (def adjust (adjust-range 0 100))#'user/adjust

user=> (adjust 75)75

user=> (adjust 101)100

Page 20: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Partial functions (currying)

(partial f arg1 arg2 arg3 & more)Takes a function f and fewer than the normal arguments to f, and returns a fn that takes a variable number of additional args. When called, the returned function calls f with args + additional args.

user=> (def hundred-times (partial * 100))#'user/hundred-times

user=> (hundred-times 5)500

Page 21: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

Function composition

user=> (def negtimes (comp - *))#'user/negtimes

user=> (negtimes 5 3)-15

user=> (def third (comp first rest rest))#'user/third

user=> (third [11 22 33 44])33

user=> (third '(:a :b :c :d)):c

Page 22: Clojure 3 Recursion, Higher-order-functions 27-Aug-15

The End