Fork me on GitHub
#beginners
<
2015-07-05
>
grounded_sage03:07:01

What does this r do? (reduce (fn [r x] (+ r (* x x))) [1 2 3]) - it's from Living Clojure

roberto03:07:30

r is an accumulator

roberto03:07:57

the result of applying fn to each element of the vector, is saved in r

roberto03:07:02

for example, when x = 1, r = 0. After applying the fn to x, r will be 1.

roberto03:07:26

when x = 2, r will be 1. After applying fn to x, r will be 5

roberto03:07:52

when x = 3, r will be 5. After applying fn to x, r will be 9.

roberto03:07:39

and since we’ve reached the end, the vector has been “reduced” to a single value: 9.

spike10:07:07

i think you’ve forgotten the (* x x) part

spike10:07:03

it’ll be (1 1) + (2 2) + (3 * 3), which will be 14

iae12:07:23

Hello everyone! I was wondering if anyone might be willing to help me with a problem regarding state.

iae12:07:37

I have the following code to create a maze, or grid, and traversal functions which actually creates the maze-like passages: http://pastebin.com/A7CKCdeQ

iae12:07:01

Usage: (link-cells maze (traverse maze binary-tree))

iae12:07:08

It works except for the linkage; my link function updates the cell, but it's not mutated. In this case I'd like to know how to mutate the cell in question defined in link-cell so that neighboring cells get updated

iae12:07:55

Oh, sorry, the cell definition is (defrecord Cell [visited? valid-dirs open-dirs])

andrut14:07:01

hey @iae, I think that's the whole point of using clojure - whenever possible, avoid mutating state; in your case, assoc is not updating the cell but it is creating a new map based on the given one

andrut14:07:00

one way to get away from this problem would be to return cells (or maze itself) from link-cell function and maybe use reduce instead of for in link-cells function

andrut14:07:30

the other way would be to use either dynamic variable or an atom but I would think twice before doing that simple_smile

iae14:07:53

Thanks for the advice @andrut; I think I know what you mean and I'll try to implement it real quick simple_smile

iae14:07:54

I'm using the Repl right now and am getting a rather nondescript error in the REPL: IllegalArgumentException No value supplied for key: cmaze.cell.Cell@4cd6d0d2 clojure.lang.PersistentHashMap.create (PersistentHashMap.java:77)

iae14:07:58

Is there a means to get the full stack trace?

iae15:07:46

Ah, I think I found the error, it's because my traverse function uses a map and returns a list instead of my Maze defrecord type, correct?http://pastebin.com/Z9xvHVNj

iae15:07:25

The solution, then, would be to use the ->Maze function: http://pastebin.com/HZUPkXSz

iae15:07:47

Imho, it seems a little cumbersome to have to do that after every operation that wants to change something in a map

iae15:07:51

Is that really necessary?

iae15:07:49

Woohoo, it seems to work now, thanks again @andrut simple_smile In case you might be interested in what the code looks like now, you can find it here: http://pastebin.com/KiGD17zH

andrut16:07:42

I'm glad it worked simple_smile

andrut16:07:40

the code looks better to me, I've got one question though: do you really need to use defrecord for Maze? why not to use simple map?

iae16:07:34

In F# you usually start out creating your domain models using type and I thought that would be a good starting point

iae16:07:57

A map was too generic for me, and from what I understand a record IS a map except it has some magic functions added to it

iae16:07:38

I'm still not entirely sure when to use records and when not; I think a good use case is when using the schema lib

iae16:07:47

Otherwise I'm still learning when to use which feature

iae17:07:05

Hm, it tells me to use a map because I'm not using protocols or interfaces, but if I skip to the defrecord point, it says "do you want to model a domain value" which is what I wanted the Maze to be

iae17:07:00

But I think I understand its point; I'll keep the flowchart up the next time I create my model simple_smile

seancorfield17:07:42

I think most people just use maps — until they get to the point where they want to define behavior specific to a domain value, since that’s the benefit of a record (implementing a protocol).

seancorfield17:07:05

Your background is in strongly-typed languages?

iae17:07:55

Yes, quite so

iae17:07:06

I program in groovy as well, but I usually prefer to type everything

seancorfield17:07:13

There’s a lot of freedom and power in letting go of types simple_smile

seancorfield17:07:12

But it’s a big change of mindset coming to Clojure, especially from strongly-typed OOP languages, so it can seem very unnatural at first.

iae17:07:13

Quite so, but I'm honestly liking it so far simple_smile

iae17:07:21

I assume that many dynamic language functions such as groovy's method_missing are also implementable in clojure

iae17:07:29

Perhaps in some other way, I haven't looked into that yet

seancorfield18:07:01

Without objects, method_missing doesn't really make sense. Either you've got a function or you haven't.

seancorfield18:07:09

But with protocols you can declare a function to behave in a polymorphic way, even for other existing types you didn't write.

iae21:07:47

Woohoo the first clojure program I actually finished without switching lisp/scheme dialects and ultimately succumbing to choice paralysis!

iae21:07:50

Feels good.

iae22:07:13

Wasn't easy, and compared to the ruby code, there is something to be said about how easy it is to just iterate over a grid and mutate the cells without having to return a new maze.

iae22:07:18

I'm not sure if I feel like I have gained anything following a more functional approach to the same problem; the ruby code is simple and easy to read, probably difficult to mess up with too

iae22:07:33

It might be a newbie problem, but switching to sets to organize a cell's traversable directions in wasnt as straightforward as I hoped. I learned that sets and maps have some pretty important differences compared to lists; functions that I expected to work the same like flatten returned an empty list.

iae22:07:10

Clojure errors are often not very helpful, at least when seen from the REPL

iae22:07:16

Structuring a clojure file is confusing at the moment, but that's because I haven't properly studied the structure of clojure files/projects. Apparently you can't put definitions under functions that need them, but unlike a language such as C++ you can't forward-declare them? This leads to the public-facing functions being interspersed with private helper functions and I find it difficulty to see which functions are part of the Cell and Maze api

akiva22:07:48

There’s the declare function but I’ve not seen it much in the wild.

iae22:07:54

Thanks for the heads up @akiva simple_smile Yes, that looks exactly like what I was looking for. I'll have to give the topic a more in-depth look before continuing to expand the project

iae22:07:02

Especially why it might not be used as much in the wild

akiva22:07:04

I usually put utility, higher-order, and generalist functions at the top or group them with a calling function and just comment the code around it.

akiva22:07:45

And put them into their own namespaces.

akiva22:07:09

I use declare generally when functions reference each other.

iae22:07:33

Doesn't sound like that would happen too often in Clojure, or?

akiva22:07:50

It can when using defrecord.

dmich23:07:49

@iae: Did I understand your earlier comment that you first did this in F#?