Fork me on GitHub
#braveandtrue
<
2018-12-10
>
felipebarros20:12:15

Hi. I'm currently at https://www.braveclojure.com/core-functions-in-depth/#Infinite_Sequences_ and having a bit of a hard time understanding that "mind bending" function. Does anybody know of a complementary article/video or whatever that could help me?

felipebarros20:12:49

Tried reading the sources for take, lazy-seq, repeat, broke the function removing the call to lazy-seq, tried searching http://clojure.org for lazyness and lazy but so far I still don't get it. I accept it works and I can use it, sure, but I would like to have the workings forcibly "realized" by my brain 🙂

felipebarros20:12:04

For instance, in the example given:

(take 8 (even-numbers))
Why does it return the 0 in the output? Where/why does it loop? Where is the state stored? Conceptually I know its inside a closure but the border is blurry in my mind.

manutter5120:12:06

Are you familiar with linked lists?

felipebarros20:12:34

More or less, this chapter kind of introduces the concept when explaining the implementation of the sequence abstraction.

felipebarros20:12:22

But yes, I think I get it.

manutter5120:12:56

Ok, that likely good enough. So if you want to traverse a linked list, you want to “get” each item in the list. Each item will be a pair of values: the “head” and the “rest”, where the “rest” is another linked list.

manutter5120:12:44

then you do whatever you want with the head, and get the next item from “rest”

manutter5120:12:10

So imagine we have a function called GET that returns “head” and “rest”,

manutter5120:12:40

We use “GET” to get the head and the rest, do something with head, and then loop back to call “GET” on the “rest”

felipebarros20:12:50

Oh, I see, it returns the 0 because in the source it calls (cons (first s) (take (dec n) (rest s))))...

felipebarros20:12:12

in the source for take, that is

felipebarros20:12:55

oh, so in that second call to take using the rest, it decreases the number passed, so that is where the loop happens... I guess?

manutter5120:12:12

Well, let’s step through it one at a time

manutter5120:12:19

First value: take calls (even-numbers 0). That’s going to give it a list with two items in it, the value 0, and a function. (It’s a lazy function , but just think of it as a function for now)

felipebarros20:12:35

so far so good

manutter5120:12:10

So take has a “head” and a “rest”, and it knows that the “head” is the first item it’s going to return, so it cranks out 0 as its first item.

manutter5120:12:41

Now, the “rest” should normally be a list, but in this case it’s a function — a lazy function.

manutter5120:12:03

Lazy functions are a special case, so take knows that to get the actual list, it needs to call the function.

manutter5120:12:40

In this case, the function is (even-numbers (+ n 2)) which is a closure, like you said.

manutter5120:12:20

So it closed over the 0, and that makes it (even-numbers (+ 0 2)) or (even-numbers 2)

manutter5120:12:58

So take calls (even-numbers 2) and gets back another list: (2, (even-numbers (+ 2 2)))

manutter5120:12:59

So the “head” is 2, and take peels that off and cranks that out as its second item.

felipebarros20:12:20

Perfect. I get this now. 🙂

manutter5120:12:39

That leaves the function as the “rest”, and again, it’s a lazy function, so it just keeps doing that over and over, for as many values as it needs.

felipebarros20:12:04

> Lazy functions are a special case, so take knows that to get the actual list, it needs to call the function.

manutter5120:12:29

Heh, I’m kind of hand-waving there — not 100% sure what the internals are doing to make that happen.

felipebarros20:12:18

Thank you so much for taking the time to help me. At least how that particular instance works is clear now 🙂

manutter5120:12:08

The basic idea is that instead of what you might call a physical list like (1 2 3 4), you get a pair with 1 value + a factory for making the next “value + factory” pair, and every time you take the value, you run the factory.

felipebarros20:12:00

Yes, excellent.

manutter5120:12:28

Or rather, the factory runs automatically, but you get the idea.

felipebarros20:12:39

It's clear now. 🙂 It's funny how things just snap into place.

manutter5120:12:54

Yeah, I struggled with it for quite a while before it finally clicked.

felipebarros20:12:37

I guess a source of confusion with how it is explained in the book is that he defines even-numbers as a multi-arity function and ends up not using it.. so I was looking at that cons and the call to lazy-seq and lost it..

felipebarros20:12:33

I guess he does use it.. haha

manutter5120:12:55

Yeah, the 0-arity is just to seed the 1-arity version.

felipebarros20:12:43

I'm trying to write it with 1-arity and I think I'm missing something on the need for a multi-arity function in this case..

felipebarros20:12:26

Hmm, maybe not. It just would be the case that you would not be able to call it without any arguments. OK.