foxlog
4/29/2015 - 8:12 AM

## clojure thinking recursively | 递归

clojure thinking recursively | 递归 clj

``````;; A loop that sums the numbers 10 + 9 + 8 + ...
(defn sums [n]
(loop [sum 0 cnt n]
(if (= cnt 0)
sum
(recur (+ cnt sum) (dec cnt)))))

(sums 10)
;=> 55``````
``````;; come from `the joy of clojure`

;; Mundane recursion
(defn pow [base exp]
(if (zero? exp)
1
(* base (pow base (dec exp)))))

(pow 2 10)
;=> 1024
(pow 1.01 925)
;=> 9937.353723241924

(pow 2 10000)
; java.lang.StackOverflowError

;; recursive call
;; to occur in the tail position
;; This new version of pow uses two common techniques for converting mundane recursion
;; to tail recursion. First, it uses a helper function kapow that does the majority of
;; the work. Second, kapow uses an accumulator acc that holds the result of the multiplication.
(defn pow [base exp]
(letfn [(kapow [base exp acc]
(if (zero? exp)
acc
(recur base (dec exp) (* base acc))))]
(kapow base exp 1)))
(pow 2N 10000)
;=> ... A very big number

``````
``````(defn elevator [commands]
(letfn
[(ff-open [[_ & r]]
"When the elevator is open on the 1st floor
it can either close or be done."
#(case _
:close (ff-closed r)
:done true
false))
(ff-closed [[_ & r]
"When the elevator is closed on the 1st floor
it can either open or go up."
#(case _
:open (ff-open r)
:up (sf-closed r)
false))
(sf-closed [[_ & r]]
"When the elevator is closed on the 2nd floor
it can either go down or open."
#(case _
:down (ff-closed r)
:open (sf-open r)
false))
(sf-open [[_ & r]]
"When the elevator is open on the 2nd floor
it can either close or be done"
#(case _
:close (sf-closed r)
:done true
false))]

(trampoline ff-open commands)))

(elevator [:close :open :close :up :open :open :done])
;=> false
(elevator [:close :up :open :close :down :open :done])
;=> true
;; run at your own risk!
(elevator (cycle [:close :open]))
; ... runs forever``````
``````;; from clojure koans

(defn factorial [n]
(loop [n   n
acc 1]
(if (= n 0)
acc
(recur (dec n) (* n acc)))))

(factorial 3) ;; 6

(factorial 4) ;;24
(factorial 5)

;; https://gist.github.com/5a43353e59b0dbc41cc3 ``````
``````;; from the joy of clojure

(def simple-metric {:meter 1,
:km 1000,
:cm 1/100,
:mm [1/10 :cm]})

;; How many meters
;; are in 3 kilometers, 10 meters, 80 centimeters, 10 millimeters?” you could use the map
;; as follows:

(-> (* 3 (:km simple-metric))
(+ (* 10 (:meter simple-metric)))
(+ (* 80 (:cm simple-metric)))
(+ (* (:cm simple-metric)
(* 10 (first (:mm simple-metric)))))
float)
;;=> 3010.81

;; Although the map is certainly usable this way, the user experience of traversing
;; simple-metric directly is less than stellar. Instead, it would be nicer to define a function
;; named convert, shown in the following listing

(defn convert [context descriptor]
(reduce (fn [result [mag unit]]
(+ result
(let [val (get context unit)]
(if (vector? val)
(* mag (convert context val))
(* mag val)))))
0
(partition 2 descriptor)))

(convert simple-metric [50:mm])``````
``````(defn char-counter [str]
(loop [counts {}
s str]
(if-not (empty? s)
(let [c (first s)]
(recur (assoc counts c (inc (get counts c 0)))
(rest s)))
counts)))

(char-counter "hello world")``````