    (lens/view user :first-name))
 
 ;; ========================================================
-;; composition
-
-;; a critical future of lenses are that they compose
-;; you can do this with the lens/comp-lenses
-;; this function takes a seq of lenses and combines them
+;; Composition
+
+;; A critical feature of lenses are that they compose.  You can do
+;; this using the `lens/comp-lenses` function that takes a seq of
+;; lenses and combines them:
 
 (def user2
   {:first-name "tobias"
    :last-name "funke"
-   :address {:city "bluethwill"
+   :address {:city "bluthville"
              :address_line "sudden vale street 23"
              :postcode "56321"}})
 
 (def user-city (lens/comp-lenses [:address :city]))
 
-(= (lens/view user2 user-city) "bluethwill")
-
-;; if you use a vector of lenses as a lens
-;; you will get the same result as calling lens/comp-lenses on the lenses
+(= (lens/view user2 user-city) "bluthville")
+
+;; If you use a vector of lenses as a lens you will get the same
+;; result as calling `lens/comp-lenses` on those lenses:
 
 (= (lens/view user2 [:address :postcode])
    "56321")
 
-;; so basically you can use lenses just like you use
-;; the clojure *-in functions
+;; so basically you can use lenses just like you use the clojure
+;; get-in/assoc-in/update-in functions:
 
 (= (get-in user2 [:address :city])
    (lens/view user2 [:address :city]))

   :last-name "funke"
   :email "tobias.funke@gmail.com"})

;; this is the raw way to define a lens
;; you call lens/lens and give it a function
;; that takes a root value in this case a user
;; and returns a pair where the first value
;; is the field. And the second value is a function
;; that takes a function of the name and returns a new user

(def first-name
  (lens/lens

(require '[clojure.string :as string])
(use 'clojure.pprint)

;; you can get the field from the root value by calling view on it
;; with the lens:

(pprint (lens/view user first-name))
;; => "tobias"

;; you can also update the field with the update function:

(pprint (lens/update user first-name string/capitalize))
;; => {:last-name "funke",
;;     :first-name "Tobias", <-- capitalized
;;     :email "tobias.funke@gmail.com"}

;; you can also write to the field with `lens/write`: this is the same
;; as doing `(update root lens (fn [_] new-value))`.

(pprint (lens/write user first-name "Newname"))
;; => {:last-name "funke",
;;     :first-name "Newname",
;;     :email "tobias.funke@gmail.com"}

;; you can also define lenses using `lens/getter-setter-lens`
;; which makes a lens from a getter and a setter function:

(def first-name2
  (lens/getter-setter-lens
   (fn [user] (:first-name user))
   (fn [user new-first-name] (assoc user :first-name new-first-name))))

;; this will give you the same lens:
(= (lens/write user first-name  "Newname")
   (lens/write user first-name2 "Newname"))

;; since using keywords to reference fields in maps is so common
;; you can use them directly as lenses:

(= (lens/write user first-name  "Newname")
   (lens/write user first-name2 "Newname")
