Fork me on GitHub
#clojure
<
2017-08-30
>
bschrag00:08:31

@noisesmith That acts just like before (didn't figure out what to do with ^:replace, or ^:merge). I'll try asking on #leiningen.

noisesmith00:08:55

the ^:replace goes after the key and before the value in the project map

noisesmith00:08:44

what happens specifically with :jvm-opts is that it concatenates options, and if two options contradict, you might get an undesirable choice from the vm, in which case you ahve to use ^:replace to get a good command line generated

donyorm01:08:12

So something funky is going on with my classpath. Right now my config namespace "cannot be found" when required in another namespace. But if I run cider-load-buffer in the config namespace, it works fine. The config namespace is included in the same directory as the other files (which work normally) and appears to have no syntax errors. What could cause this?

donyorm01:08:23

I'm running this with boot and cider in spacemacs if that matters

donyorm01:08:32

Ok, just got a new error. Apparently the config namespace can't compile because of this error:

Caused by java.lang.RuntimeException
   Internal graphics not initialized yet
. What causes that?

donyorm01:08:27

Figured it out, apparently I was trying to create a javafx before the screen had been initialized, which was causing an intermitten error in the config namespace

yogidevbear10:08:48

Are there any online resources / books that would teach about the underlying architecture of Clojure? I'm looking for things that would help me to understand how Clojure actually works (code compilation/execution, behind the scenes processes, caveats with things like macros, etc.) as opposed to things like syntax and results of running code.

val_waeselynck11:08:17

For Clojure JVM I assume? Working knowledge of Java and the JVM helps. Also check out "life of a clojure expression" on YouTube

val_waeselynck12:08:26

Another instructive thing to do is decompile the .class files generated by the compilation and try to decipher what's going on. You can do that in IntelliJ for instance.

bronsa10:08:29

not that i'm aware of

donyorm11:08:02

Is there any sort of tutorial/better documentation for building an aether repositiory with pomegrante, as boot and lein do?

Alex Miller (Clojure team)18:08:15

depending what you want to do, you might find the new tools.deps.alpha lib to be useful, either for direct use or stealing https://github.com/clojure/tools.deps.alpha

vandr0iy11:08:55

Anybody can tell me why is it impossible to define a put method in a defrecord? For instance, this works:

(defprotocol Foo
  (get-file [a b c])

  (put-file [d e f]))

(defrecord Bar []
  Foo
  (get-file [a b c] 1)
  (put-file [d e f] 2)
This doesn't:
(defprotocol Foo
  (get-file [a b c])

  (put [d e f]))

(defrecord Bar []
  Foo
  (get-file [a b c] 1)
  (put [d e f] 2)
Because this Exception gets thrown: CompilerException java.lang.ClassFormatError: Duplicate method name&signature in class file ch/deepimpact/black/infra/document_store/webdav/Bar Can't find anything on my-favorite-search-engine

xtreak2911:08:14

Maybe it's due to the fact a defrecord is a macro and expands to a put method in itself. Might help : https://gist.github.com/skelter/5091143#file-replsession-clj-L56

vandr0iy12:08:08

That's more or less what I thought were happening. In this case, shouldn't there be a list of "forbidden" words in the documentation? Also, if I try the same trick with the get function - which is defined just about 2 lines below and is part of core.clj - or keySet, not part of core.clj but still defined in the same place - or even putAll, function with the same body as put in the macroexpantion you mentioned in the gist, - no exception gets thrown. Except, of course, for the usual warning for the core function overwrite in case of get:

(defprotocol Foo
  (get [a b c])

  (putt [d e f]))

(defrecord Bar []
  Foo
  (get [a b c] 1)
  (putt [d e f] 2) )
Warning: protocol #'user/Foo is overwriting function get
WARNING: get already refers to: #'clojure.core/get in namespace: user, being replaced by: #'user/get
=>Foo
=>user.Bar
(defprotocol Foo1
  (get [a b c])

  (putAll [d e f]))

(defrecord Bar1 []
  Foo1
  (get [a b c] 1)
  (putAll [d e f] 2) )
=> Foo1
=> user.Bar1

vandr0iy13:08:01

so, do I report it as a bug or maybe there's something that I missed and this is documented behaviour?

dominicm15:08:50

Do you have same problem with deftype and reify?

dominicm15:08:28

I think that the put in your protocol should end up namespaced, so in confused about this behavior.

dominicm15:08:20

@vandr0iy I cannot replicate your error with simple example.

dominicm15:08:11

Odd. I cannot define a get on a record, but I can define a put

dominicm15:08:06

bar.core=> (ns bar.core2 (:refer-clojure :exclude [get]))
nil
bar.core2=> (defprotocol Pa (get [this a]))
Pa
bar.core2=> (defrecord Ra [] Pa (get [this a] (prn this a)))

CompilerException java.lang.ClassFormatError: Duplicate method name&signature in class file bar/core2/Ra, compiling:(/tmp/form-init2000030803215161610.clj:1:1) 
bar.core2=> (ns bar.core3 (:refer-clojure :exclude [get]))
nil
bar.core3=> (defprotocol Pa (put [this a]))
Pa
bar.core3=> (defrecord Ra [] Pa (put [this a] (prn this a)))
bar.core3.Ra

dominicm16:08:50

In clojure 1.9.0-alpha17 I can define both without issue. What clojure version are you seeing this on?

dominicm16:08:25

Really weird: I see this ONLY with a lein repl, not with a boot one.

vandr0iy07:08:41

So, yeah, I looked at this thing again with a colleague. Apparently, given the nature of the error, it's very closely tied to the generated Java code and the signatures of your records' methods. It seems that the Object that comes out of the defrecord has a bunch of evil interfaces in clojure.lang.* that have some methods that defrecord as a macro silently implements (macroexpand a defrecord call and look at it closely: https://gist.github.com/skelter/5091143#file-replsession-clj-L56). However, the methods of the protocol you're implementing collide with the methods of the said interfaces - and, if the signature is the same - everything works as intended; but if it's different - it blows a CompilerException in your face. For example, you can define a put function with 2 arguments, but it's impossible to do that with 3. For get it goes the other way - you can't define it with 2 args, which has, in fact, happened to you:

(defprotocol Foo1
  (get-file [a b c])

  (put [d e]))

(defrecord Bar1 []
  Foo1
  (get-file [a b c] 1)
  (put [d e] 2) )
This works - as opposed to my original message where (put [d e f]) doesn't.

mx200014:08:01

How can I get the outer tag in enlive where the inner tag matches some selector

mx200014:08:23

I always get the inner tag as return

mx200014:08:30

Found a solution -> its using html/has

cgrand16:08:01

It's the right solution

lincpa15:08:03

Notepad++ 7.5.1 patch for Clojure by modifying Lisp model. https://github.com/linpengcheng/ClojureBoxNpp , autocomplete don't need nrepl or JVM. It's the fastest clojure IDE. welcome to #notepad_plus_plus .

dominicm15:08:55

@lincpa how does autocomplete work without jvm or nrepl? Parsing for def and defn?

lincpa15:08:36

Pre-build an XML file for all symbols of a project and Dependencies Lisp. XML is placed in Notepad++\plugins\apis

dominicm15:08:05

ctags is good approach, but incomplete. In the dynamic environment clojure provides, it is more complete to use jvm.

delaguardo15:08:17

am i right and this lisp.xml file should be regenerated if I would like to introduce new dependency?

lincpa15:08:19

autocomplete isn't uses ctags, ctag.exe is used to jump to define

lincpa15:08:14

lisp.xml has 40k+ symbols of jvm and Dependencies. And with the automatic completion of the document based word, it's enough.

lincpa15:08:38

It's perfect for reading code and modifing code.

gdeer8116:08:46

I saw a library for compiling Clojure code to php. it hasn't been touched in 5 years but I'm just always amazed when I google "Clojure to <x>" and see the first hit is a github project

Garrett Hopper19:08:03

Should I be able to reference a global atom defiend in a cljc file from a clj file?

Garrett Hopper19:08:23

Are cljc files not supposed to have the same namespace as its clj and cljs counterparts? Perhaps it's just a boot requirement?

ghadi20:08:30

I don't think you can have foo.cljc as well as foo.clj

Alex Miller (Clojure team)20:08:23

no, you cannot. platform-specific takes precedence and foo.clj will be loaded in this case.

Garrett Hopper20:08:29

I thought I had done just that in the past, but I guess now.

hmaurer20:08:31

I find myself writing (into {} (map (fn [[k v]] ...) m)) a lot; is there a standard lib function for this?

hmaurer20:08:38

(mapping over a map)

hmaurer20:08:32

to be more specific, mapping over the values of a map

noisesmith20:08:38

no, but one small improvement is to take m out of the map call and make it a separate arg

hmaurer20:08:18

sorry, I am not sure what you mean?

noisesmith20:08:31

I was referring to the transducer version - changing (into {} (map f c)) into (into {} (map f) c) - same output, does less work, more flexible

tanzoniteblack20:08:44

@hmaurer that is not part of the standard lib

hmaurer20:08:08

@tanzoniteblack yeah it’s not indeed. There doesn’t seem to be anything like that part of the std lib 😞

tanzoniteblack20:08:16

generally, I just do this by using reduce-kv and creating a new map (which is what you're doing anyways); i.e.

(reduce-kv (fn [m k v] (assoc m (my-fn k) v) {} m)
, but that's only a small improvement over what you have there

tanzoniteblack20:08:24

you could of course always do it with specter as well

hmaurer20:08:44

@tanzoniteblack oh I see. I had written a reduce version but thought map would be cleaner

matthavener20:08:02

map is faster as well

dpsutton20:08:11

couldn't you easily walk this?

dpsutton20:08:23

or would that descend into vals and that's not what you want?

matthavener20:08:25

(into {} (map f) arg) is arguably more idiomatic now

hmaurer20:08:25

spectre looks neat

hmaurer20:08:35

@dpsutton yeah I don’t want to descend into vals

noisesmith20:08:56

walking is likely the slowest solution, and does weird things potentially, if you have maps in the values of the map

hmaurer20:08:29

@matthavener I should read about transducers then!

nathanmarz20:08:34

specter is the highest performance by quite a bit, up to 65% faster than reduce-kv

nathanmarz20:08:03

equally as important specter doesn't change sorted maps into unsorted maps

matthavener20:08:37

wow, into with a transducer is much slower than i expected

nathanmarz20:08:15

into with a transducer is great for sequences, not so much for maps

nathanmarz20:08:24

since wrapping key/value pairs in vectors adds a ton of overhead

matthavener20:08:26

is it all the intermediate 2-tuples?

nathanmarz20:08:57

here's a more up to date version of that benchmark with more cases:

Benchmark: transform values of a small map (500000 iterations)

Avg(ms)		vs best		Code
62.560 		 1.00 		 (transform MAP-VALS inc data)
88.289 		 1.41 		 (map-vals-map-iterable data inc)
89.023 		 1.42 		 (reduce-kv (fn [m k v] (assoc m k (inc v))) {} data)
96.205 		 1.54 		 (persistent! (reduce-kv (fn [m k v] (assoc! m k (inc v))) (transient {}) data))
125.09 		 2.00 		 (map-vals-map-iterable-transient data inc)
126.38 		 2.02 		 (reduce-kv (fn [m k v] (assoc m k (inc v))) (empty data) data)
262.15 		 4.19 		 (into {} (map (fn [e] [(key e) (inc (val e))])) data)
376.26 		 6.01 		 (zipmap (keys data) (map inc (vals data)))
424.99 		 6.79 		 (into {} (for [[k v] data] [k (inc v)]))
429.51 		 6.87 		 (into {} (map (fn [e] [(key e) (inc (val e))]) data))
437.50 		 6.99 		 (transform [ALL LAST] inc data)

********************************

Benchmark: transform values of large map (600 iterations)

Avg(ms)		vs best		Code
84.023 		 1.00 		 (persistent! (reduce-kv (fn [m k v] (assoc! m k (inc v))) (transient clojure.lang.PersistentHashMap/EMPTY) data))
86.743 		 1.03 		 (transform MAP-VALS inc data)
95.225 		 1.13 		 (persistent! (reduce-kv (fn [m k v] (assoc! m k (inc v))) (transient {}) data))
101.18 		 1.20 		 (reduce-kv (fn [m k v] (assoc m k (inc v))) {} data)
125.21 		 1.49 		 (reduce-kv (fn [m k v] (assoc m k (inc v))) (empty data) data)
149.87 		 1.78 		 (into {} (map (fn [e] [(key e) (inc (val e))])) data)
168.20 		 2.00 		 (map-vals-map-iterable-transient data inc)
185.75 		 2.21 		 (map-vals-map-iterable data inc)
196.57 		 2.34 		 (transform [ALL LAST] inc data)
214.91 		 2.56 		 (zipmap (keys data) (map inc (vals data)))
218.59 		 2.60 		 (into {} (for [[k v] data] [k (inc v)]))
219.78 		 2.62 		 (into {} (map (fn [e] [(key e) (inc (val e))]) data))

nathanmarz20:08:35

so 4x faster than transducers for small maps, 80% faster for large maps

hmaurer20:08:54

@nathanmarz are there similarities between spectre navigators and haskell-style lenses?

nathanmarz20:08:49

yes, though I'm not familiar enough with haskell lenses to give a detailed answer

nathanmarz20:08:30

haskell splits its navigator-equivalents into multiple types (lens, traversal), while specter has a single interface for all navigators

hmaurer20:08:30

out of curiosity, did you base Spectre on research? or is it more of a practical implementation of what felt nice to work with?

hmaurer20:08:41

oh, I see 🙂

nathanmarz20:08:00

it's the result of unifying a crazy amount of use cases in the problem domain

nathanmarz20:08:36

starting with basic compound use cases and evolving from there

nathanmarz20:08:25

a lot of my personal work involves recursive DAG's, so making really involved transformations on those elegant guided the development of specter a lot

chalcidfly21:08:47

Having trouble with lazy sequences & would love some help from a more experienced clojurian: https://stackoverflow.com/questions/45970034

noisesmith21:08:01

@chalcidfly that can’t be lazy because there’s no step where you can use the head but not evaluate the tail

noisesmith21:08:31

it does a direct self recursion, and to get the n+1 element, you need to do the recursive call

noisesmith21:08:03

(lazy-seq …) should pretty much always have a call to cons inside - or something that lets you return the next item of the list without recurring

chalcidfly21:08:38

@noisesmith I see… what about appending to a vector?

noisesmith21:08:47

vectors are never lazy

noisesmith21:08:23

also conj isn’t lazy, because it needs to check the type of its first arg

chalcidfly21:08:33

what about appending to a list then?

noisesmith21:08:00

you can’t append to a list without realizing the whole thing - though you can do concat but wanting to do that recursively usually means you are making a mistake

noisesmith21:08:27

the standard pattern is (lazy-seq (cons (make-next arg) (make-rest other args))

chalcidfly21:08:01

hmmmm…. gotta rethink this one

chalcidfly21:08:04

thanks for the help!

noisesmith21:08:33

so in your case it would probably be something like (lazy-seq (cons (f val (first coll)) (red val (rest coll)))

bronsa21:08:45

isn't that concat?

noisesmith21:08:41

it’s basically map

noisesmith21:08:07

it’s a pseudo-code though - just trying to show something closer to what he’s trying to get

noisesmith21:08:13

it’s just a question of pulling the next item out of the recursive call so it can be used immediately without the recursion happening

noisesmith21:08:38

I think you’ll need to make other small changes to make that work - but the code will get simpler

chalcidfly22:08:00

updated with an answer

vandr0iy07:08:41

So, yeah, I looked at this thing again with a colleague. Apparently, given the nature of the error, it's very closely tied to the generated Java code and the signatures of your records' methods. It seems that the Object that comes out of the defrecord has a bunch of evil interfaces in clojure.lang.* that have some methods that defrecord as a macro silently implements (macroexpand a defrecord call and look at it closely: https://gist.github.com/skelter/5091143#file-replsession-clj-L56). However, the methods of the protocol you're implementing collide with the methods of the said interfaces - and, if the signature is the same - everything works as intended; but if it's different - it blows a CompilerException in your face. For example, you can define a put function with 2 arguments, but it's impossible to do that with 3. For get it goes the other way - you can't define it with 2 args, which has, in fact, happened to you:

(defprotocol Foo1
  (get-file [a b c])

  (put [d e]))

(defrecord Bar1 []
  Foo1
  (get-file [a b c] 1)
  (put [d e] 2) )
This works - as opposed to my original message where (put [d e f]) doesn't.