   ;; outside of the let scope
   (println x))
 
-(no-mutation "Existential Angst Person")
-;; =>
+(fact "Kafka Human is in it's own scope"
+  (no-mutation "Existential Angst Person")
+  => nil)
 ;;Existential Angst Person
 ;;Kafka Human
 ;;Existential Angst Person
 
+
+;; recursive proplem solving:
 (defn sum
-  ([vals] (sum vals 0))
+  ([vals] (sum vals 0))  ;; --1-- default value for accumulator
   ([vals accumulating-total]
-    (if (empty? vals)
+    (if (empty? vals)    ;; --2-- empty vals is the base condition
       accumulating-total
       (sum (rest vals) (+ (first vals) accumulating-total)))))
 
-  (fact "test sum"
-    (sum []) => 0
-    (sum [1]) => 1
-    (sum [39 5 1]) => 45)
+(fact "evaluate sum"
+  (sum [39 5 1])   => 45   ;; single-arity - call 2-arity
+  (sum [39 5 1] 0) => 45
+  (sum [5 1] 39)   => 45
+  (sum [1] 44)     => 45
+  (sum [] 45)      => 45   ;; base case is reached, so return the accumulator
+  45               => 45 )
+
+;; should use 'recur' for more efficient looping
+(defn sum-r
+  ([vals]
+     (sum vals 0))
+  ([vals accumulating-total]
+     (if (empty? vals)
+       accumulating-total
+       (recur (rest vals) (+ (first vals) accumulating-total)))))
+
+(fact (sum-r [39 5 1]) => 45 )
 
 
-;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; function compostion instead of attribute mutation
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (require '[clojure.string :as s])
 

  (Thread/sleep 1000)
  x)

(sleepy-identity "Mr. Fantatstico")

(def memo-sleepy-identity
  "does calculation once, then returns imediatly"
  (memoize sleepy-identity))

(memo-sleepy-identity "Mr. Fantatstico")

  [text]
  (s/replace (s/trim text) #"lol" "LOL"))

(fact
  (clean "My boa constrictor is so sassy lol!  ")
  => "My boa constrictor is so sassy LOL!")

;; use a chain of function calls instead of progressively mutating an object


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; cool things to do with functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(fact "chaining function is pretty common style so function called 'comp'"
  ((comp s/lower-case s/trim) " Unclean string ")
  => "unclean string")

;; 'def' create a function
(def my-lower-trim-1 (comp s/lower-case s/trim))
(fact
  (my-lower-trim-1  " Unclean string ")
  => "unclean string")

;; an implementation of 'comp' that composes two functions
(defn two-comp
  [f g]
  (fn [& args]
    (f (apply g args))))

(def my-lower-trim-2 (two-comp s/lower-case s/trim))

(fact
  (my-lower-trim-2 " Unclean string  ")
  => "unclean string")

(def sum-times2 (two-comp  #(* 2 %) +))

(fact
  (sum-times2 1 2 3)
  => 12)

;; define a new version of 'comp'
(defn my-comp
  [f & funs]
  (if (empty? funs) f    ;; base case - returned composed function
      (recur (fn [& args]
                 (f (apply (first funs) args)))
               (rest funs))))

(fact "works like two-comp"
  ((my-comp s/lower-case s/trim) " Unclean string ")
  => "unclean string")

(fact "works like regular 'comp'"
  ((my-comp s/reverse s/lower-case s/trim) " Unclean string ")
  => "gnirts naelcnu")

(def sum-times2' (two-comp  #(* 2 %) +))
