loop

added
1.0

ns
clojure.core

type
macro

(loop bindings & body)

Evaluates the exprs in a lexical context in which the symbols in
the binding-forms are bound to their respective init-exprs or parts
therein. Acts as a recur target.

                ;; looping is recursive in Clojure, the loop construct is a hack so that
;; something like tail-recursive-optimization works in clojure.

user=> (defn my-re-seq [re string]
         "Something like re-seq"
         (let [matcher (re-matcher re string)]

           (loop [match (re-find matcher) ;loop starts with 2 set arguments
                  result []]
             (if-not match
               result
               (recur (re-find matcher)    ;loop with 2 new arguments
                      (conj result match))))))

#'user/my-re-seq

user=> (my-re-seq #"\\d" "0123456789")
["0" "1" "2" "3" "4" "5" "6" "7" "8" "9"]


            
                ;; Read decoded MP3 data in loop (requires mp3plugin.jar on class path)
;; http://java.sun.com/javase/technologies/desktop/media/jmf/mp3/download.html 

(import '(javax.sound.sampled AudioSystem AudioFormat$Encoding))

(let [mp3-file (java.io.File. "tryout.mp3")
      audio-in (AudioSystem/getAudioInputStream mp3-file)
      audio-decoded-in (AudioSystem/getAudioInputStream AudioFormat$Encoding/PCM_SIGNED audio-in)
      buffer (make-array Byte/TYPE 1024)]
  (loop []
    (let [size (.read audio-decoded-in buffer)]
      (when (> size 0)
        ;do something with PCM data
\t(recur)))))

            
                (loop [x 10]
  (when (> x 1)
    (println x)
    (recur (- x 2))))

;;=> 10 8 6 4 2
            
                (defn find-needle [needle haystack]
  ;loop binds initial values once,
  ;then binds values from each recursion call
  (loop [needle needle
         maybe-here haystack
         not-here '()]

    (let [needle? (first maybe-here)]

      ;test for return or recur
      (if (or (= (str needle?) (str needle))
              (empty? maybe-here))

        ;return results
        [needle? maybe-here not-here]

        ;recur calls loop with new values
        (recur needle
               (rest maybe-here)
               (concat not-here (list (first maybe-here))))))))

user=>(find-needle "|" "hay|stack")
[\\| (\\| \\s \\t \\a \\c \\k) (\\h \\a \\y)]
            
                ; makes a simple template function that can be used in mustache way: http://mustache.github.com/
(defn template [tpl env]
  (loop [tpl tpl
         env env]
    (cond (empty? env)
          tpl
          :else
          (let [[key value] (first env)]
            (recur (try (clojure.string/replace tpl 
                                                (re-pattern (str "\\\\{\\\\{" (name key) "\\\\}\\\\}")) 
                                                value)
                        (catch Exception e tpl)) 
                   (rest env))))))
            
                (loop [iter 1
       acc  0]
  (if (> iter 10)
    (println acc)
    (recur (inc iter) (+ acc iter))))

;; => 55
;; sum from 1 to 10
            
                ;; loop is the recursion point for recur. The symbols in loop's 
;; binding-forms are bound to their respective init-exprs and 
;; rebound to the values of recur's exprs before the next execution 
;; of loop's body.

;; calculate the factorial of n

(loop [n (bigint 5), accumulator 1]
  (if (zero? n)
    accumulator  ; we're done
    (recur (dec n) (* accumulator n))))

;;=> 120N


;; square each number in the vector

(loop [xs (seq [1 2 3 4 5])
       result []]
  (if xs
    (let [x (first xs)]
      (recur (next xs) (conj result (* x x))))
    result))

;; => [1 4 9 16 25]
            
                ; A loop that sums the numbers 10 + 9 + 8 + ...

; Set initial values count (cnt) from 10 and down
(loop [sum 0 cnt 10]
    ; If count reaches 0 then exit the loop and return sum
    (if (= cnt 0)
    sum
    ; Otherwise add count to sum, decrease count and 
    ; use recur to feed the new values back into the loop
    (recur (+ cnt sum) (dec cnt))))
            
                (loop [i 0]  
  (when (< i 5)    
    (println i)    
    (recur (inc i)); loop i will take this value
))
            
                ;; Iterating over a collection using loop

;; 1. First call (seq xs) on the given argument and then check for nil 
;; 2. Then call next/first and use these.

(loop [xs (seq [1 2 3 4 5])
       result []]
  (if xs
    (let [x (first xs)]
      (recur (next xs) (conj result (* x x))))
    result))

;; the same loop can be written using destructing,
;; but the compiler will generate two consecutive
;; seq calls and is slightly less efficient.

(loop [[x & r :as xs] (seq [])
       result []]
  (if xs
    (recur r (conj result (* x x)))
    result))
            
                ;;basic loop example #1

(loop [x 0
       result []]
  (if (< x 10)
    (recur
      (inc x)
      (conj result x)) result))
;;[0 1 2 3 4 5 6 7 8 9]

;;basic loop example #2
(def citrus-list ["lemon" "orange" "grapefruit"])

(defn display-citrus [citruses]
  (loop [[citrus & citruses] citruses]
    (println citrus)
    (if citrus (recur citruses))))

(display-citrus citrus-list)