Fork me on GitHub
#beginners
<
2015-11-10
>
binduwavell01:11:56

Clojure for the Brave and True includes the following comparison in the chapter on Macros:

binduwavell01:11:03

(list '+ 1 (inc 1))
; => (+ 1 2)

`(+ 1 ~(inc 1))
; => (clojure.core/+ 1 2)

surreal.analysis01:11:01

Unfortunately, the github style of including the language after triple ticks doesn't work

surreal.analysis01:11:15

I'd love to get syntax highlighting in Slack, but it seems a ways away

binduwavell01:11:36

Thanks surreal.analysis, sorry for spamming those edits simple_smile

binduwavell01:11:59

My question is in the first form, shouldn't the 1 be quoted like so: (list '+ '1 (inc 1))

surreal.analysis01:11:33

Both are correct

binduwavell01:11:41

I assume that '1 and 1 are identical and therefore it doesn't matter, but I wonder about the distinction

surreal.analysis01:11:25

I think the idea is that, because '1 and 1 are always equivalent, might as well write less

binduwavell01:11:27

Is there a good reason that Daniel wrote this example without quoting the 1 (other than the obvious that it's shorter.)

surreal.analysis01:11:10

That said, I'm far from an expert on writing macros, so if someone else tells you otherwise, they're probably correct simple_smile

binduwavell01:11:51

OK, so while I'm here I do have another question

binduwavell01:11:31

I got completely lost with the treatment of dereferencing and namespaces. I've been programming for a very long time and I get the concept of namespaces as they apply to many other languages... I.e. for scoping/organizing things so that names don't overwrite each other.

binduwavell01:11:12

For some reason I just got completely lost when Daniel started talking about dereferencing with @

binduwavell01:11:32

Does anyone have a simple sample or learning resource that could help clear this up for me?

binduwavell01:11:34

FWIW I've written a fair amount of C so I get how * and & work there... It seemed to me that refs and dereferencing them was quite different in clojure/lisp than the similar concepts in C...

binduwavell01:11:47

Re-read the sections around interning, this is what I think is going on: (def great-books ["East of Eden" "The Glass Bead Game"]) This creates a variable holding the vector of books this variable is associated with the fully qualified name (in reader-form) #'user/great-books (obviously I'm in the user namespace). Apparently #'user/great-books is the actual variable that resolves to the stored-value. (deref #'user/great-books) returns the stored vector. Can also be written @#'user/great-books. Apparently referencing 'great-books in the user namespace is not exactly the same. @'great-books (while in the user namespace) throws an exception about not being able to cast a Symbol to a concurrent.Future... So, 'great-books is a symbol which when evaluated (eval 'great-books) in the user namespace produces the value stored in the #'user/great-books Var... To me having a Var (#'user/great-books) and a symbol ('great-books) that are magically tied to each other during evaluation is pretty confusing, but I guess at the end of the day, it's just exposing what is hidden in other languages... The fact that they have different reader forms is confusing to me, but I'm sure there is a great reason for this... Hope I can figure out what it is simple_smile

alexmiller02:11:09

A namespace has a table of symbol to var, where a var holds a value

alexmiller02:11:50

In Clojure, almost everything evaluates to itself

alexmiller02:11:12

The two important exceptions are symbols and lists

alexmiller02:11:15

Symbols cause a lookup using the current namespace context to find the var whose which evaluates to the value in the var

alexmiller02:11:55

Lists evaluate all the elements, then invoke the first element as a function

alexmiller02:11:12

I'm fudging in several ways but this is the general model

alexmiller02:11:51

A symbol is just the "name" but the var is the actual box holding the value

alexmiller02:11:35

Derefing a symbol doesn't work because it's just a name. You can evaluate the symbol to a var and deref that though

alexmiller02:11:57

Quoting (from your above question) just turns off evaluation. Because most things eval to themselves, it doesn't really matter. Generally quoting is mostly used on symbols and lists because they have these extra capabilities (lookup and invocation)

alexmiller02:11:31

@binduwavell: see comments above ^^

kamn04:11:50

I need a non-marco and for the merge-with function

kamn04:11:59

(merge-with #(every? identity [%1 %2]) a b)

kamn04:11:10

Is the smallest I have come up with

kamn04:11:26

Anyone have a better way?

binduwavell13:11:54

@alexmiller: thanks very much!

binduwavell14:11:54

I was just reading through some posts on slow Clojure startup times. One thread in the comments suggested that moving away from Vars to immutable values drastically improves Clojure performance (including startup time).

binduwavell14:11:49

Reading between the lines, does that mean the point of this indirection from symbols to Vars had to do with supporting notability?

alexmiller14:11:49

not sure what you mean by moving from vars to immutable values. the main avenue for improving clojure startup times is to lazily load the classes implementing the functions held in vars. Right now that loading (in clojure.core) consumes a significant amount of time. there is a branch of the clojure code that does this.

alexmiller14:11:58

the downside is that you then have to add a check for whether to do the load and that check hurts jit inlining and makes every subsequent invocation about 50% slower (talking ns per call here)

alexmiller14:11:03

so there are tradeoffs

binduwavell14:11:57

@alexmiller Notability? Should have read Immitability! :) dyac

binduwavell14:11:47

@alexmiller presumably we could use static analysis to determine a good set of stuff to evaluate at startup and then fall back on checking for everything else...

drewverlee16:11:35

I'm hoping someone can help me with a mental block i'm having as I transition from more OOP style languages (Python, Ruby) to a more functional language (Java... jk i mean clojure). Here is the toy problem... You want to find the area's of a series of shapes and store these areas somewhere.

[shape, shape, shape] => [area_of_shape, area_of_shape, area_of_shape]
In python I would give each object a class and each would have a method area() that gave the area depending on the characteristic of the class. Then I would loop over the shapes and store their areas in some other structure.
areas = [shape.area() for shape in shapes]
I feel like without having an object to implement what defined what area means for it then i would have to have one function for reach data structure that represents the shape and the function that wants to collect the areas into a list would have to ask what shape it is.
if shape == "square":
   area.append(area_of_square(shape))
However, i'm probably missing some other design within a functional language that would simplify this. Any suggestions?

drewverlee16:11:17

maybe the problem is that my list has more then one type of shape...

swizzard16:11:25

@drewverlee: how are your shapes represented?

drewverlee16:11:25

@swizzard: I hadn't thought that part out. I assume if i were doing this in python they would each have a unique set of attributes.

class Square:
    self.side = side

class Rectangle:
    self.width = width
    self.height = height 
if were talking about how would i model them in a functional language then i would assume a hasmap would be the natural representation.

swizzard16:11:49

so if you’re gonna use maps, you can just do a multimethod

swizzard16:11:54

(defmulti area :type)
(defmethod area :square [{side :side}] (* side side))
(defmethod area :circle [{r :radius}] (* radius radius Math/pi))

swizzard16:11:40

and then pass it e.g. {:type :square :side 10}, {:type :circle :radius 10}

xeqi16:11:44

@drewverlee: different code needs to run for each type of shape, but you want to be able to call it the same way. There is not a design that eliminates the need for a polymorphic dispatch there. The dispatch could happen with an if/cond/condp/etc, a mutltimethod, or a protocol. The difference between these choices is if you want to be able to add new shapes, and how to figure which function to eventually end up at

xeqi16:11:09

^ thats the same way I would implement it if doing hashmap/multimethod

drewverlee16:11:33

@xeql , Does it come down to code organization then? In functional example i group together the functionality and in oop i group together the objects?. drew grits teeth as he realizes how obvious that sounds. Maybe a less obvious observation would be that if it comes down to representation then isn't this just a tooling problem? Couldn't a magical ide transition between the multimethod implementation and the class one with methods?

swizzard16:11:03

well so multimethods aren’t really equivalent to class methods, per se

drewverlee16:11:11

also thanks @swizzard for the example!

swizzard16:11:51

( @drewverlee i’m a fellow pythonista, so i know these feels)

swizzard16:11:55

the closest thing to class methods clojure has would probably be protocols

swizzard16:11:37

but one of the nice things about fp, imho, is that you can focus more on data than on containers

swizzard16:11:56

you can just output maps and then pass them around and it’s fine

xeqi16:11:27

@drewverlee: in order: not really, sometimes, I don't understand the question, yes. Sometimes multimethod (or protocol) functions are grouped near the original definition. But when an external user wants to build a new type it is common to have the extensions around the type declaration. Are you familiar with the https://en.wikipedia.org/wiki/Expression_problem?

xeqi16:11:28

For example, in https://github.com/weavejester/duct/issues/5 there is a suggestion of extending a protocol. In one instance it extends a java class this is usually done near where the function definition happens. The second example creates an inline object that implements the protocol. This groups the definition at the type creation

xeqi16:11:50

a similiar principle applies to multimethods

xeqi16:11:27

where you place the extensions goes down to where you can place them, and what you think looks good

drewverlee16:11:51

@xeqi, thanks!

xeqi16:11:06

@drewverlee heh, not sure that helps much.

drewverlee17:11:33

@xeqi, it helped a ton.

drewverlee17:11:56

Now someone explain everything from this talk: https://www.youtube.com/watch?v=IOiZatlZtGU, because i think i just saw something amazing but I dont know what it was 😕

drewverlee17:11:08

(not a serious request)

roberto18:11:26

that was the best Strangeloop talk evar.

sveri20:11:20

@drewverlee: Superlambda! thanks for the link, really interesting and I want that shirt!

drewverlee23:11:34

@colin.yates: can we start a room and just talk about the propositions as types talk? Im not sure I have the foundation to get everything he talked about. But I feel I would be a lot better off even with a general understanding.

limix23:11:41

Hi all, what does ~ do in clojure? I see it in several places like so: [{:list/one ~subquery} {:list/two ~subquery}]

akiva23:11:08

Short story: ~ is unquote. That is within as syntax quoted (`) block ~ will unquote the associated symbol i.e. resolve it in the current context.

limix23:11:46

ah ok got it

limix23:11:52

thank you