Fork me on GitHub
#clojure
<
2019-05-26
>
Jamie Rumbelow11:05:26

Can the clojure compiler detect side effects in functions? Can it decide at compile-time whether a function is pure?

orestis12:05:24

I wouldn’t rely on that to be exhaustive though! There’s nothing in the language to make such a guarantee.

Jamie Rumbelow12:05:14

I’m interested in whether the compiler could automatically memoize all pure functions. Could effect massive speed improvements, minimal amounts of memory increase, with very little risk

gklijs12:05:48

I don't think it's minimal. Like any function that does something on a data structure using an uuid is unlikely to be called twice with the same.

mfikes13:05:42

An interesting aside on the ClojureScript side, once Google Closure knows a function is pure, it does certain optimizations with it. Here is one case where it is incorrect: https://github.com/google/closure-compiler/issues/3079

mfikes13:05:26

I suppose they have a notion of "no side effects" in this case, which is different than "pure" via their terminology https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler#nosideeffects-modifies-thisarguments

respatialized15:05:46

Yeah my initial impression was that you could probably do a whole dissertation on this topic and still only come up with a method that only works on a restricted scope of language features

lilactown16:05:47

Clojure as it’s written can not. But a runtime certainly could detect at runtime and do certain optimizations. Or if code was written to be explicit about its effects

Jamie Rumbelow17:05:30

Okay, all interesting stuff - thanks everyone!

p-himik16:05:59

It has probably been discussed numerous times but I can't find any answer. I have these macros:

(defmacro format-query [q]
  `(cond-> ~q
     (map? ~q) (sql/format :quoting :ansi)))

(defmacro query [c q params]
  `(jdbc/query ~c ~(format-query q) ~params))
The issue is that (query 1 2 3) expands to (jdbc/query 1 2 3) whereas I want it to expand to (jdbc/query 1 (cond-> 2 ...) 3). Is it possible to do so?

lilactown16:05:56

based on your code, i’m not sure why it would expand to (jdbc/query 1 2 3)

lilactown16:05:40

but I think in this case you can change format-query to be a function, rather than a macro

lilactown16:05:46

and that might be what you want?

vlaaad16:05:29

should be

(defn format-query [q]
  `(cond-> ~q
     (map? ~q) (sql/format :quoting :ansi)))

(defmacro query [c q params]
  `(jdbc/query ~c ~(format-query q) ~params))

vlaaad16:05:16

first macro should be a function @p-himik

p-himik16:05:48

Sure. But now I can't use format-query anywhere except for other macros. I guess a solution in this case would be to extract the common part to another macro. That's what I'll probably do. Thanks!

p-himik16:05:44

Can you help me understand why it's expanded the way it is with two defmacro? The way I read it: ~ in ~(format-query q) unquotes this part, so that the macro is expanded here. It expands in a form (cond-> ...). The thing I cannot understand is why this form is being computed during macro expansion.

lilactown18:05:17

It was being computed during macro expansion because you used the macro in a macro

lilactown18:05:40

So the format-query macro was being executed, expanded and then the query macro continued evaluating and expanding

lilactown18:05:08

I have a need for a sparse vector. Any ideas how I might represent that?

lilactown18:05:24

It's a semantic thing rather than a perf thing. I need the inverse of nth: construct a vector with a value at position n.

lilactown18:05:02

And then I also need a way of merging the sparse vectors...

Chris O’Donnell18:05:22

What other operations do you need to do?

lilactown19:05:26

Pretty much just those

lilactown19:05:54

What I'm trying to do is, for example start with a source like [1 2] and project it using second. So it would produce 2. Then, I could change the projection to 3 and use that to update the source to [1 3]

p-himik19:05:12

"Project it" and "change the projection" sound a lot like what Specter does.

lilactown19:05:16

I'm basically implementing a lens. I am trying to figure out how to implement it myself rather than use a lib like specter 😅

Chris O’Donnell19:05:42

The operations you mention above sound like they could be easily done on a hash map instead of a vector with regular old assoc and merge. It's not entirely clear to me how those things fit in to your lens implementation.

Chris O’Donnell19:05:01

I suppose you could hold onto the novelty in a hash map and do the merge by associng the novelty from the hash map into the vector.

lilactown19:05:06

Right, the issue is the source to the data is a vector and that needs to be preserved

Bravi21:05:22

hi everyone. is this an overkill?

(some? (some-> project :images :thumbnail))

Bravi21:05:29

to check for non-nil value

Bravi21:05:57

looks a bit weird 😄

vlaaad21:05:28

why not just (-> project :images :thumbnail)? thumbnail is probably not a boolean, so just having a value where you do check for nil is ok

vlaaad21:05:08

or (-> project :images :thumbnail some?) if are you really into booleans 🙂

kulminaator21:05:52

btw. if you want to get your clojure hat on on the raspberry pi 3 b+ .... installing zulu jdk & lein works surprisingly easy

kulminaator21:05:06

but trying to use openjdk from adoptopenjdk won't work , something with ssl connections and elliptic ciphers is broken there 😞 ... so zulu instead and life is good

Bravi21:05:12

@vlaaad I thought it would throw an exception if I did it without some->

vlaaad21:05:32

keywords, when called as functions on nils just return nil (:a nil) => nil

Bravi21:05:13

gotcha, thank you