Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clojure - using loop and recur with a lazy sequence

If I am returning a lazy-seq from a function like this:

(letfn [(permutations [s]
              (lazy-seq
               (if (seq (rest s))
                 (apply concat (for [x s]
                                 (map #(cons x %) (permutations (remove #{x} s)))))
                 [s])))])

If I use loop recur like below, will the list be eagerly evaluated?

(loop [perms (permutations chain)]
       (if (empty? perms)
         (prn "finised")
         (recur (rest perms))))

If it is eagerly evaluated, can I use loop..recur to lazily loop over what is returned from the permutations function?

like image 227
dagda1 Avatar asked Jan 11 '15 07:01

dagda1


1 Answers

The list is lazily evaluated by your loop-recur code.

You can try it out yourself. Let's make permutations print something every time it returns a value by adding a println call.

(defn permutations [s]
  (lazy-seq
   (if (seq (rest s))
     (apply concat (for [x s]
                     (map #(cons x %) (permutations (remove #{x} s)))))
     (do
       (println "returning a value")
       [s]))))

When using loop, let's also print the values with we're looping over with (prn (first perms).

(loop [perms (permutations [1 2 3])]
  (if (empty? perms)
    (prn "finised")
    (do
      (prn (first perms))
      (recur (rest perms)))))

Here's what it prints:

returning a value
(1 2 3)
returning a value
(1 3 2)
returning a value
(2 1 3)
returning a value
(2 3 1)
returning a value
(3 1 2)
returning a value
(3 2 1)
"finished"

As you can see, "returning a value" and the value lines are interlaced. The evaluation of the lazy seq can be forced with doall. If you loop over (doall (permutations [1 2 3])), first it prints all the "returning a value" lines and only then the values.

like image 72
Miikka Avatar answered Sep 21 '22 14:09

Miikka