# Code question

**URL:** https://clojureverse.org/t/code-question/4931
**Category:** Beginners
**Created:** [October 4, 2019, 8:52pm UTC](https://clojureverse.org/t/code-question/4931 "2019-10-04T20:52:02Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![sunjlee](https://clojureverse.org/user_avatar/clojureverse.org/sunjlee/32/2130_2.png) [@sunjlee](https://clojureverse.org/u/sunjlee)
#### Post date: [October 4, 2019, 8:52pm UTC](https://clojureverse.org/t/code-question/4931/1 "2019-10-04T20:52:02Z")

</div>

I have the following code from manning clojure essential reference book page 467.

(defn fast-producer [n]  
(-\>\> (into () (range n))  
(map #(do (println “produce” %) %))))

(defn slow-consumer [xs]  
(keep  
#(do  
(println “consume” %)  
(Thread/sleep 2000))  
xs))

(slow-consumer (fast-producer 5))

;; the output is:

produce 4  
consume 4 ; … wait 2 seconds  
produce 3  
consume 3 ; … wait 2 seconds  
produce 2  
consume 2 ;; wait 2 seconds  
produce 1  
consume 1 ;; waiat 2 seconds  
produce 0  
consume 0 ;; wait 2 seconds

My question is:  
why it’s not the case that all the produce gets printed before consumer?  
i.e. why producer and consuer alternates?

thanks

sun

---

<div class="post-metadata">

### Author: ![andy.fingerhut](https://clojureverse.org/user_avatar/clojureverse.org/andy.fingerhut/32/1244_2.png) [@andy.fingerhut](https://clojureverse.org/u/andy.fingerhut)
#### Post date: [October 4, 2019, 9:25pm UTC](https://clojureverse.org/t/code-question/4931/2 "2019-10-04T21:25:53Z")

</div>

> [@sunjlee](#):
>
> (slow-consumer (fast-producer 5))

The function `map` that you are calling in function fast-producer is lazy. In some cases it will produce values up to 32 or so ahead of the consumer, but in many cases it will never do any work to produce another value until some consumer advances past the part of the sequence that has been created so far.

---

<div class="post-metadata">

### Author: ![sunjlee](https://clojureverse.org/user_avatar/clojureverse.org/sunjlee/32/2130_2.png) [@sunjlee](https://clojureverse.org/u/sunjlee)
#### Post date: [October 5, 2019, 12:55am UTC](https://clojureverse.org/t/code-question/4931/3 "2019-10-05T00:55:13Z")

</div>

thatnks for the reply, but how the context switching works?

In other words, initially fst-producer do nothing.  
and now slow-consumer gets invoked.  
upon seeing xs, it asks fast-producer to generate data.  
But I don’t understand how this “context switching” takes place.

thanks

---

<div class="post-metadata">

### Author: ![didibus](https://clojureverse.org/user_avatar/clojureverse.org/didibus/32/951_2.png) [@didibus](https://clojureverse.org/u/didibus)
#### Post date: [October 5, 2019, 7:39am UTC](https://clojureverse.org/t/code-question/4931/4 "2019-10-05T07:39:47Z")

</div>

You can think of map as doing:

```auto
[#(do (println “produce” 0) 0), #(do (println “produce” 1) 1), #(do (println “produce” 2) 2), ...]

```

And then keep as doing:

```auto
[(fn[] (println “consume” #(do (println “produce” 0) 0))
(Thread/sleep 2000))), (fn[] (println “consume” #(do (println “produce” 1) 1))
(Thread/sleep 2000))), ...]

```

So now when something loops over that and reads each element, you can see that as the first element is realized, it would first print “produce 0” and then print “consume 0” and then sleep 2 seconds, and then move the realizing the next element, etc.

---

<div class="post-metadata">

### Author: ![kingnuscodus](https://clojureverse.org/user_avatar/clojureverse.org/kingnuscodus/32/3212_2.png) [@kingnuscodus](https://clojureverse.org/u/kingnuscodus)
#### Post date: [October 9, 2019, 12:59am UTC](https://clojureverse.org/t/code-question/4931/5 "2019-10-09T00:59:23Z")

</div>

By definition, a lazy sequence generates/computes its elements on demand, as they are requested. With that in mind, it helps to think through the computing steps required when a single element - e.g. the first one - is requested:

1. Within `slow-consumer`'s `keep`'s argument function, an element from the enclosing input is requested in order to print it out
2. That element is taken from the output of `fast-producer`, which has produced none yet
3. Within `fast-producer`, the function within map is invoked on the next element, prints it and returns it
4. Finally, `slow-consumer`'s `keep`'s arg. fn has something to chomp on, prints the value, then calls Thread/sleep
5. `Thread/sleep` always returns `nil`, and therefore `nil` is returned from `keep`'s argument fn
6. As an element is being requested, but none has been found so far (`keep` is not allowed to return `nil` values, see also previous step), `keep` invokes the argument function on its next input element (the next element output by fast-producer), etc

So to answer your original question, the consumer and producer values alternate because the consumer takes its values from a lazy sequence (the producer), whose values are generated on demand. At the (first) time slow-consumer requests an element from its input, only that element is made available by its input collection (since it is generated on demand by fast-producer), so there is no context switching as you suggested, but just a single value output by the first function (fast-producer) into the client function requesting it (the slow-consumer).

However there is a second issue in your specific example, due to a lazy sequence’s obligation to provide an element, even when none is available (step 6 above), which may have added to your initial confusion.

We can illustrate the above by playing around a bit with your example and separating the phases of the pipeline:

(def output (slow-consumer (fast-producer 5)))  
;; #'user/output  
(first output)  
;; produce 4  
;; consume 4  
;; produce 3  
;; …

(def from-producer-only (fast-producer 5))  
;; #'user/from-producer-only  
(first from-producer-only)  
;; produce 4  
;; 4  
;;user\>

(def from-consumer-only (slow-consumer (reverse (range 5))))  
;; #'user/from-consumer-only  
(first from-consumer-only)  
;; consume 4  
;; consume 3  
;; consume 2  
;; …

One more thing about lazy sequences worth noting however: the side-effects happen only once, i.e. when the computation occurs. All subsequent requests for an element come from memory:  
(first from-producer-only)  
;;4

And, as a direct consequence of that, all retained elements consume space, which can become a problem if the lazy sequence is large and is referenced for a long time (e.g. by a var).

---

<div class="post-metadata">

### Author: ![system](https://clojureverse.org/uploads/default/original/2X/5/51079bf9e4b7d9466242c06cf1e43b9f8bd6da14.png) [@system](https://clojureverse.org/u/system)
#### Post date: [April 8, 2020, 12:59pm UTC](https://clojureverse.org/t/code-question/4931/6 "2020-04-08T12:59:29Z")

</div>

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.
