Fork me on GitHub
#braveandtrue
<
2018-08-27
>
moo17:08:17

in the functional-programming chapter with pegthing they (defn tri* ...) and later on (def tri (tri*)) many functions refer to tri (without the star). What is the idea behind this?

moo17:08:00

e.g. this function refers to tri and not tri*

(defn triangular?
  "Is the number triangular? e.g. 1, 3, 6, 10, 15, etc"
  [n]
  (= n (last (take-while #(>= n %) tri))))

manutter5117:08:43

In this particular example, tri* is a function that calculates a lazy sequence. Without the star it's just a def, not a defn, so it's basically using the tri* function to calculate the sequence for you one time so that you can then use it more than once without re-calculating it.

manutter5117:08:33

In other words it's like a singleton: once you've run tri* once, you don't need to run it again. Just keep a copy in tri and use that sequence.

moo17:08:57

thinking java it’s like

if (_instance == null) { tri = tri*}
return tri
?

moo17:08:14

The page reads The next expression calls tri*, actually creating the lazy sequence and binding it to tri: (def tri (tri*)) /end quote. What does actually creating mean here? Because it seems like we’re just binding the function to another name.

moo17:08:19

Is it like this? tri* always returns a new lazy-seq and tri returns the same instance of that lazy-seq?

manutter5117:08:15

"actually creating" means it's calling the function that generates the lazy seq. Notice the parens. If you do (def tri tri*), then that would be binding the function to another name, but that's not what it's doing. (def tri (tri*)) is actually running the tri* function, and the result of running it is being stored in tri

moo17:08:37

so the return value of (tri*) is getting bound to tri

moo17:08:06

Thank you again man! 🙂

👍 4
moo17:08:44

This chapter is odd, I’m sure I’m not catching everything. I don’t know if I should go very very slow or just start trying the excerises

moo17:08:16

It’s a bigger “chunk” than other chapters thus far

manutter5117:08:24

I haven't read it, but given that it's called "functional programming," I'd recommend "all of the above" 🙂

manutter5117:08:05

I have a bit of pseudo-code I use to express kind of the "zen" of functional programming...

manutter5117:08:41

10 LET X = 5;
20 PRINT X;// <== prints "5"
30 X = X + 1;
40 PRINT X; // <== prints "6"

manutter5117:08:18

So from line 20 we know that X equals 5, and from line 40 we know that X equals 6, so from line 30 we know that 5 equals 6.

manutter5117:08:21

When you read that and say, "Wait, WAT??" you're smacking head-first into the difference between functional programming and imperative programming.

moo17:08:18

The immutable aspect?

manutter5117:08:30

Immutability is a big part of it

manutter5117:08:32

One way to look at it is that with imperative programming, every variable has two dimensions that you have to know in order to get the value of the variable: its name, and its time.

manutter5117:08:10

If all you have is the name ("X"), then you can't really know the correct value of X because it's different on line 20 than it is on line 40.

manutter5117:08:24

You have to know it's name, the value it has at different times, and what the "current" time is. So really, it could conceivably have an unlimited number of values, according to what time it is.

manutter5117:08:53

Functional programming is more mathematical, and the thing about math is that in general you're solving equations in which time is not part of the problem. For any one value of X, there's only one value of sin X, for example.

manutter5117:08:28

You don't have to worry that the value of X somehow changed between the time you said "X" and the time you said "sin X"

moo18:08:21

Yes, that seems like a wonderful thing and it feels like part of the pitch to try clojure and FP in general

moo18:08:35

debugging complex state is so tricky

moo18:08:48

Also, … in a lot of my programming experience due to the problems I’ve needed to solve, I just smashed data around. Now looking back, I wonder if making all those data-object-classes was needed

manutter5118:08:54

So the brain-bending part of learning FP is learning how to see functions as descriptions of the "timeless" relationship between values as opposed to seeing them as imperative recipes for beating things into some kind of desired shape.

moo18:08:55

anyways. 🙂

moo18:08:24

Yeah, what you said last makes sense

manutter5118:08:25

but yeah, I'd say, read slow, try the exercises, and be ready to back track and re-read things as individual concepts become clearer

manutter5118:08:36

and of course feel free to post questions here

moo18:08:11

thanks. Yeah. I’m on my second reading of this ch. Now I see how the program continues without looping. Basically it’s always the last call in each function that moves you along. But I don’t follow how the board is getting manipulated. I’ll keep going. It’s day two on this ch. 🙂

moo18:08:03

so for lazy sequences, are the parts that are “reified” cached/saved somehow?

manutter5118:08:14

Yeah, they stay in memory, and they'll eventually bite you if you leave them (aka "holding on to the head").

moo18:08:05

as in you need to stop referring for gc to work?

manutter5118:08:15

They get garbage collected when there are no longer any references to them, but in the tri/`tri*` example, the tri var is always pointing to the first item in the lazy seq, so it will never be gc'ed

moo18:08:38

I thought tri is pointing to the sequence itself

moo18:08:04

because there is (take-while (conditions) tri) going on

manutter5118:08:11

exactly, yes, but more specifically, it's pointing to the head of the sequence

moo18:08:17

oh gotcha

moo18:08:32

à la linked lists

manutter5118:08:49

yes, exactly

manutter5118:08:12

and the first item in the list is the "head," hence the expression "holding on to the head"

moo18:08:42

so, that’s a reason why you’ll need to use let,.. to have local variables when needed

manutter5118:08:09

Exactly. (def tri ...) is immutable, so it will always hold onto the head.

manutter5118:08:26

You're better off with a (let ...) if you think your lazy-seq might ever get too big. You can get away with it here because the peg-board game is only going to realize/reify a relatively small portion of that lazy seq