## 6. Functional Programming If you don’t love something, it’s not functional, in my opinion.
— Yves Behar

## Functions recap

Functions always return a value

• Usually not `nil`

• `(inc 1)``2`

• `(println "hi")``nil` causes a side-effect

• All Input/Output is considered a side-effect

## Pure functions

``````(str "hi" "there")
;=> "hithere"``````
• No side-effects occur

• Inputs always produce the same corresponding output

## Side effects

``````(rand-int 100)
;=> 42``````
• Not a pure function

• Returns a useful result, but changes every time

• Modifying a hidden state (or based on it)

## Side effects

``````(def x 1)
;=> #'x``````
• Returns a var

• Side-effect: `x` can now be resolved

## Side effects are useful

• Databases

• Files

• User interfaces

## Many Clojure functions are pure

``````(conj [1 2] 3)
;=> [1 2 3]``````
• `conj` does not add something to a vector

• `conj` returns a new vector value

## Persistent immutable data structures

• Clojure implements efficient immutable data structures

• Creating derivative values is cheap

• Using a Java vector would require duplicating the vector

• Clojure uses shared structure

## Pure functions are desirable

• easier to combine

• easier to test

• easier to debug

• easier to parallelize

## How can you change a variable?

``````(def v [1 2])
(conj v 3)
;=> [1 2 3]``````
``````v
;=> [1 2]``````
• `v` remains unchanged

• Manage change explicitly

## Use Atoms for mutatable state

``````(def a (atom 1))
(swap! a inc)
(deref a)
;=> 2``````

Shorthand for `deref`:

``````@a
;=> 2``````

## Atoms work with any data structure

``````(def a (atom [1 2]))
(swap! a conj 3)
@a
;=> [1 2 3]``````

## Separate side effects out

• Keep side-effects co-located

• See atoms:

• Pure function to calculate the next state

• Atom to manage

• Logic is separate from the side effect

• Keep logic pure

## Do not

```(defn f [x]
(def y 2)
(+ x y))```

```(defn f [x]
(let [y 2]
(+ x y)))```

## apply

``````(max 1 2 5 3)
;=> 5``````

What if you have a sequence of many numbers?

``````(def numbers [1 2 3 4 5 6 7])
(apply max numbers)
;=> 7``````
 `apply` means to call or invoke

## partial

In Clojure we often pass functions as values

`(partial + 1)`

Returns a function that is equivalent to:

```(fn [& args]
(apply + 1 args))```
• captures an argument

• partial application

## partial returns a new function

Produces a function:

``````((partial + 1) 2 3)
;=> 6``````
``````(map (partial / 1) (range 1 5))
;=> (1 1/2 1/3 1/4)``````

## Alternative to partial:

``````(map #(/ 1 %) (range 1 5))
;=> (1 1/2 1/3 1/4)``````

## Functions on sequences

To embrace Clojure

is to think in sequences and data structures

## Sequences

``````(cons 1 ())
;=> (1)``````
``````(cons 3 (cons 2 (cons 1 ())))
;=> (3 2 1)``````
``````(range 10)
;=> (0 1 2 3 4 5 6 7 8 9)``````

## Careful

Clojure can produce infinite sequences

`(range)`
• Don’t do this in the REPL

• Press control-c to cancel the REPL if you did

## take and drop

Limit the number of items to consume:

``````(take 5 (range))
;=> (0 1 2 3 4)``````
``````(take 5 (drop 5 (range)))
;=> (5 6 7 8 9)``````

## filter and remove

``````(filter odd? [1 2 3 4])
;=> (1 3)``````
``````(remove nil? [1 2 nil 3])
;=> (1 2 3)``````
• filter and remove are higher order functions

• They take a function and a sequence

• They return a sequence of values

## Most things are seqable

``````(seq #{"a" "b" "c"})
;=> ("a" "b" "c")``````
``````(seq "string")
;=> (\s \t \r \i \n \g)``````
``````(seq {:a 1, :b 2})
;=> ([:a 1] [:b 2])``````

Clojure collections implement `ISeq`

Even Java types like strings and iterables

## Empty sequences

`seq` returns `nil` on empty sequences

``````(seq ())
;=> nil``````
``````(empty? ())
;=> true``````
 Common to use `(seq xs)` instead of `(not-empty xs)` or `(not (empty? xs))`

## map

`map` calls a function for every element in a sequence:

``````(map inc [1 2 3 4])
;=> (2 3 4 5)``````
• `map` `inc` over `[1 2 3 4]`

• Result is a sequence

• Not to be confused with the map datastructure

• Name is similar, behavior is similar keys → values

## map over multiple sequences

``````(map + [1 2 3] [10 10 10])
;=> [11 12 13]``````

## Chaining operations over seqs

Output sequences can input for other functions:

``````(filter odd? (map inc [1 2 3 4]))
;=> (3 5)``````

Keeps odd numbers from the result of `map` `inc`

## Compose

`(g (f x))`

"compose" really just means "put together"

Composition is aided by

• Idempotence

• Immutability

• Purity

## Aggregate with reduce

Reduce takes a function, initial value, and sequence:

``````(reduce * 1 [2 3 4])
;=> 24``````

Performs `(* 1 2)`, then `(* 3)`, then `(* 4)`

Multiplication called 3 times

``````(reduce * [1 2 3 4])
;=> 24``````

The initial value can be left out, if so it is the first element

## reduce

``````(reduce
(fn step [acc x]
(* acc x))
1
(range 2 5))
;=> 24``````
• Step function takes 2 arguments; aggregate and item

• Step function called for every item

• Aggregate returned

• Aggregate can be anything…​ commonly a map

## group-by

``````(group-by count ["the" "quick" "brown" "fox"])
;=> {3 ["the" "fox"], 5 ["quick" "brown"]}``````
• Produced a map

• 3 letter words ["the" "fox"]

• 5 letter words ["quick" and "brown"]

• Can we do this with reduce?

• `frequencies`

## Sequences are loop abstractions

`filter` is like a Java loop:

```for (i=0; i < vector.length; i++)
if (condition)
result.append(vector[i]);```

`map` is like a Java loop:

```for (i=0; i < vector.length; i++)
result[i] = func(vector[i]);```

`reduce` is like a Java loop:

```for (i=0; i < vector.length; i++)
result = func(result, vector[i]);```

## Sequence abstractions

• Names for loops

• Recognize different kinds of loops

• Worth the effort to learn

• Reasoning more succinctly

• Communicating more precisely

• Writing less code that does more

## Sequences and lambda expressions

Anonymous functions:

`#(< % 3)`

Handy for adding small snippets of logic:

``````(filter #(< % 3) (range 10))
;=> (0 1 2)``````
``````(map #(if (odd? %) "odd" "even")
[1 2 3 4 5])
;=> ("odd" "even" "odd" "even" "odd")``````

More concise, descriptive, composable than loops

## Creating sequences

``````(range 5)
;=> (0 1 2 3 4)``````
``````(repeat 3 1)
;=> (1 1 1)``````
``````(partition 3 (range 9))
;=> ((0 1 2) (3 4 5) (6 7 8))``````

## Transpose

``````(apply mapv vector [[1 2 3]
[4 5 6]])
;=> [[1 4]
;    [2 5]
;    [3 6]]``````

## Tricky

Common situation in Java:

```for (i=1; i < v.length; i++)
print v[i] + v[i-1];
=> 3 5 7 9```

Using the previous value in the sequence

Can we represent this as a sequence?

Imagine two identical sequences offset slightly:

```  [1 2 3 4 5]
[1 2 3 4 5]```

## map over both sequences

Recall that `map` can take multiple sequences:

``````(map + [1 3] [2 4])
;=> (3 7)``````

`rest`:

``````(def v [1 2 3 4 5])
(rest v)
;=> (2 3 4 5)``````

Put them together:

``````(map + v (rest v))
;=> (3 5 7 9)``````

## Visually

```v        => (1 2 3 4 5)
(rest v) => (2 3 4 5)```
• Sequences are of different lengths

• map stops when the smallest sequence is exhausted

• Produces a new sequence of the pairwise sums:

`(3 5 7 9)`

## Sequences beat loops

• Must comprehend the entire loop

• Loop bodies grow and change → more complexity

• Loop “off by one” mistakes

• Testing loops requires invasion

• Duplication of loops to customize similar operations

• Loops are not composable

• Loops are easy to write, but do not provide leverage

## New requirements

Multiply all of those numbers together

```result = 1;
for (i=1; i < v.length; i++)
result *= (v[i] + v[i-1]);
=> 945```
• Invasive to the imperative loop

• The change occurs inside the loop

• Intertwined

## Sequence solution

Compose `reduce` with the original `map` expression:

``````(reduce * (map + v (rest v)))
;=> 945``````
• `reduce`: Aggregate by multiplication the sequence

• `map`: adding items together from two sequences

• `pairing`: the sequence of elements in v, adjacent to the rest of v

This is dense, but descriptive code…​ if you know the vocabulary

## Sequence solution

• Unit test operations

• Unit test the component sequences

• Reuse sequences

• Reason about transformations as composable parts

## Sequences summary

Sequences are loop abstractions that allow you to ignore the implementation details

• `filter` keeps items in a sequence according to a predicate

• `map` calls a function over input sequence(s)

• `reduce` aggregates a sequence, returns a single value

## The “no loops” challenge

• Spot a loop

• Stop and think about what the loop represents

• Rewrite the loop as sequence operations instead

``````(reduce * (filter odd? (map inc v)))
;=> 15``````
• Functions offer combinatorial power

• Simple functions + sequence operations

• To read this code, work from inside out

• Finding the inside is a challenge

## Solution: order forms inside first

Name intermediary results:

``````(let [incs (map inc v)
odd-incs (filter odd? incs)]
(reduce * odd-incs))
;=> 15``````

## Or use a thread last

``````(->> v
(map inc)
(filter odd?)
(reduce *))
;=> 15``````
• Unwraps nested function calls

• Avoids naming steps

Similar to thread last, passes value in first position:

``````(-> 42
(/ 2)
(inc))
;=> 22``````

For empty expressions, the parens are optional:

``````(-> 42
(/ 2)
inc)
;=> 22``````

## Data structures are functions

``````(get {:a 1 :b 2} :a)
;=> 1``````
``````({:a 1 :b 2} :a)
;=> 1``````
``````(map {:a 1, :b 2} [:a :b])
;=> (1 2)``````
• Maps are functions

• They delegate to `get`

## Keywords are functions

``````(:a {:a 1 :b 2})
;=> 1``````
``````(map :a [{:a 1} {:a 2} {:a 3}])
;=> (1 2 3)``````

`get` `:a` for each element in a sequence

``````(map (fn [m]
(get m :a))
[{:a 1} {:a 2} {:a 3}])
;=> (1 2 3)``````

## Sets are functions

``````(get #{1 2 3} 2)
;=> 2``````
``````(#{1 2 3} 2)
;=> 2``````
``````(remove #{nil "bad"} [:a nil :b "bad" "good"])
;=> (:a :b "good")``````

## Vectors are functions

``````(get [1 2 3] 0)
;=> 1``````
``````([1 2 3] 0)
;=> 1``````

## Defaults

`get` can be passed a `not-found` value:

``````(get {} :a "default")
;=> "default"``````

Datastructures as functions do too:

``````({:a 1, :b 2} :c -1)
;=> -1``````

## Avoid side-effects in lazy sequences

``````(let [message "Hello"]
(map (fn [x]
(println message x))
(range 10))
(println "Bye"))
;;; Bye
;=> nil``````
 Hello is not printed

## Exercises

See manual end of section 6

``````(defn sum-between [a b]
(apply + (range a (inc b))))
(sum-between 3 5)
;=> 12``````
``````(defn powers-of [n]
(iterate #(* % n) 1))
(take 5 (powers-of 2))
;=> (1 2 4 8 16)``````

``````(defn shorten [s]
(remove #{\a \e \i \o \u} s))
(apply str (shorten "Clojure sets are functions"))
;=> "Cljr sts r fnctns"``````

``````(defn fractions []
(map / (repeat 1) (rest (range))))
(take 5 (fractions))
;=> (1 1/2 1/3 1/4 1/5)``````
``````(defn fraction-powers [n]
(map / (repeat 1) (powers-of n)))
(take 5 (fraction-powers 2))
;=> (1 1/2 1/4 1/8 1/16)``````

``````(defn fib-step [[a b]]
[b (+ a b)])
(defn fib-seq []
(map first (iterate fib-step [1 1])))
(take 10 (fib-seq))
;=> (1 1 2 3 5 8 13 21 34 55)``````

## Challenge 2: Processing files

Insuricorp branches collect applications for the “corgi cover” policy and periodically send them to headquarters in a large comma separated text file. You have been tasked with processing the files using the validation logic you built earlier.

## Part 1:

Create a function that opens a file called corgi-cover-applications.csv and converts every row into a data structure and prints it. Next use that data structure as an input to your validation function and print the result. See `slurp`, `line-seq`, `clojure.string/split`.

## Part 2:

The downstream Insuricorp systems will only be operating on corgi cover applications that pass your eligibility check. But the invalid corgi cover applications need to be sent back to the branches so that they can follow up with the customers on why they are not eligible. Create a new function that opens two output files and writes to them based upon your eligibility check. The files should be called `eligible-corgi-cover-applications.csv` and `ineligible-corgi-cover-applications.csv`.

## Part 3:

A request has come in from several Insuricorp branches that if a person is ineligible for corgi cover, a short reason be supplied. That way the sales reps don’t have to spend time figuring out what they need to tell the customer. Create a new validation function that instead of returning a boolean, returns nil if no problems are found, or returns a string with the reason if a problem is found. Create a new processing function that splits the applications into two files based on the new validator.

## Part 4:

As part of the Megacorp merger, the downstream systems are converting to JSON format. Create a new function that writes JSON data to a eligible-corgi-cover-applications.json file