braveandtrue

https://www.braveclojure.com/
felipebarros 2018-12-10T20:02:15.001800Z

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?

felipebarros 2018-12-10T20:05:49.004Z

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 🙂

felipebarros 2018-12-10T20:09:04.005700Z

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.

2018-12-10T20:10:06.006300Z

Are you familiar with linked lists?

felipebarros 2018-12-10T20:10:34.006800Z

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

felipebarros 2018-12-10T20:12:22.008600Z

But yes, I think I get it.

2018-12-10T20:12:56.009100Z

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.

felipebarros 2018-12-10T20:13:16.009500Z

OK

2018-12-10T20:13:44.010Z

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

2018-12-10T20:14:10.010600Z

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

2018-12-10T20:14:40.011500Z

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

felipebarros 2018-12-10T20:14:50.011800Z

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

felipebarros 2018-12-10T20:15:12.012400Z

in the source for take, that is

2018-12-10T20:15:32.013Z

Yeah

felipebarros 2018-12-10T20:16:55.014700Z

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?

2018-12-10T20:17:12.015300Z

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

felipebarros 2018-12-10T20:17:19.015700Z

OK

2018-12-10T20:18:19.016800Z

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)

felipebarros 2018-12-10T20:18:35.017200Z

so far so good

2018-12-10T20:19:10.017900Z

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.

2018-12-10T20:19:41.018600Z

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

2018-12-10T20:20:03.019100Z

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

2018-12-10T20:20:40.019700Z

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

felipebarros 2018-12-10T20:21:06.020300Z

OK

2018-12-10T20:21:20.020700Z

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

felipebarros 2018-12-10T20:21:49.021400Z

OK

2018-12-10T20:21:58.021600Z

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

2018-12-10T20:22:59.022600Z

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

felipebarros 2018-12-10T20:23:20.023300Z

Perfect. I get this now. 🙂

2018-12-10T20:23:39.023700Z

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.

2018-12-10T20:23:54.023900Z

Cool 🙂

felipebarros 2018-12-10T20:24:04.024100Z

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

2018-12-10T20:24:29.024900Z

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

2018-12-10T20:25:01.025800Z

Magic

1
felipebarros 2018-12-10T20:25:18.026200Z

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

2018-12-10T20:27:08.028100Z

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.

felipebarros 2018-12-10T20:28:00.028300Z

Yes, excellent.

2018-12-10T20:28:28.029Z

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

felipebarros 2018-12-10T20:28:39.029200Z

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

2018-12-10T20:28:54.029600Z

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

felipebarros 2018-12-10T20:31:37.030900Z

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..

felipebarros 2018-12-10T20:36:33.032Z

I guess he does use it.. haha

2018-12-10T20:36:55.032900Z

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

felipebarros 2018-12-10T20:37:43.033700Z

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..

felipebarros 2018-12-10T20:38:26.034700Z

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

2018-12-10T20:38:32.035Z

Exactly.

felipebarros 2018-12-10T20:38:49.035200Z

Awesome 😄

felipebarros 2018-12-10T20:38:55.035400Z

Thanks again!

2018-12-10T20:39:00.035600Z

:thumbsup: