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 "Something like re-seq" [re string] (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 (recur)))))
(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))))
;; 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)
;;loop general strategy ;;given a collection of numbers [1 2 3 4 5], ;;return a new collection [10 20 30 40 50] (def my-vector [1 2 3 4 5]) (defn my-new-vector [coll] (loop [remain coll final-vec []] (if (empty? remain) final-vec (let [[unit & remaining] remain] (recur remaining (into final-vec [(* 10 unit)])))))) (my-new-vector my-vector) ;;[10 20 30 40 50] ;;to sum all the elements from the newly created collection: (reduce + (my-new-vector my-vector)) ;;150
;; loop -> recur sample with fizzbuzz code. (defn fizzbuzz [n] (loop [f [] i 1] (if (< n i) f (recur (conj f (cond (zero? (mod i 15)) "fizzbuzz" (zero? (mod i 3)) "fizz" (zero? (mod i 5)) "buzz" :else i)) (inc i))))) (println (fizzbuzz 100)) ;; output is ;; [1 2 fizz 4 buzz fizz 7 8 fizz buzz 11 fizz 13 14 fizzbuzz 16 17 fizz 19 buzz fizz 22 23 fizz buzz 26 fizz 28 29 fizzbuzz 31 32 fizz 34 buzz fizz 37 38 fizz buzz 41 fizz 43 44 fizzbuzz 46 47 fizz 49 buzz fizz 52 53 fizz buzz 56 fizz 58 59 fizzbuzz 61 62 fizz 64 buzz fizz 67 68 fizz buzz 71 fizz 73 74 fizzbuzz 76 77 fizz 79 buzz fizz 82 83 fizz buzz 86 fizz 88 89 fizzbuzz 91 92 fizz 94 buzz fizz 97 98 fizz buzz]
Evaluates the exprs in order, then, in parallel, rebinds the bindings of the recursion point to the ...
trampoline can be used to convert algorithms requiring mutual recursion without stack consumption....
Evaluates test. If logical true, evaluates body in an implicit do.
Repeatedly executes body while test expression is true. Presumes some side-effect will cause test ...
List comprehension. Takes a vector of one or more binding-form/collection-expr pairs, each follow...
Repeatedly executes body (presumably for side-effects) with bindings and filtering as provided by ...
f should be a function of 2 arguments. If val is not supplied, returns the result of applying f to...
bindings => name n Repeatedly executes body (presumably for side-effects) with name bound to in...
"Acts as a recur target."
What's a recur target? A recurring target? A recursive target? I'm not a big fan of abbreviations or ambiguous terms.
Wouldn't it be awesome if a script could annotate all occurrences of glossary terms? Or automatically wrap glossary terms in anchor tags linking to their definition?
The problem loop
is trying to solve is that recursively calling the same function on the JVM is expensive and doesn't scale. It might work if your data structure is a thousand levels deep but it will fail badly with a depth of millions of levels.
What is not possible on the JVM is what is called "tail-call optimization". loop
is like a while
loop in java, except that if you don't call recur
(with the correct number of arguments) the loop will exit. In while-loop terms, recur
avoids that a break
statement is executed.
int counter = 0; while (true) { if (counter < 10) { // recur counter = inc(counter); } else { break; } }
In that sense loop
is a recur target as in "target for recursion".
I wish the word recur in this document linked to the recur function. That'd be... awesome.
It really should (and will) show up in the 'vars in' section.
The problem is that recur is a special form, and is not parsed out correctly like other vars. This will be fixed in the future.
Majority of loop
s that novices write can be expressed more elegantly using 3 fundamental functions map
, filter
and reduce
. Or using list comprehension for
.
To be clear, there's no technical reason the JVM can't support tail recursion (despite some complications to do with call stacks and security) - it just doesn't happen to support them currently.
People have been requesting this enhancement for at least a decade - here's one proposal, for example.