#clojure log - Jun 06 2015

The Joy of Clojure
Main Clojure site
Google Group
IRC
List of all logged dates

0:29 amalloy: luxbock: (defmacro on-error-goto-next ...)

0:42 luxbock: (into {} x) is always eager right?

0:42 i.e. I don't have to wrap the for in (into {} (for [...])) into a doall

0:43 justin_smith: luxbock: iirc into is as strict as the data structure, since it is just apply conj

0:43 luxbock: ah ok

0:43 justin_smith: $source inot

0:43 lazybot: Source not found.

0:43 justin_smith: $source into

0:43 lazybot: into is http://is.gd/caQYZB

0:44 justin_smith: well not *just* reduce conj, but essentially :)

0:44 luxbock: right, I should've known that

3:00 spacepluk: hi, is there any way to get a repl running on ios with lein-fruit?

3:15 Viesti: hum, which is more idiomatic, (clojure.string/join "" xs) or (apply str xs)?

3:29 alexyakushev: If you need it once per namespace, apply str is fine. Otherwise it's better to import join

3:30 That's my rule of a thumb

3:31 Besides, separator argument to join is optional

3:31 ,(clojure.string/join [1 2 3])

3:31 clojurebot: "123"

3:45 amalloy: use whichever one you want. nobody is very religious about this, except apparently alexyakushev

3:48 alexyakushev: Psst, wanna *join* this new cool cult?

3:49 amalloy: Jokes aside, I expect apply anything version to be slower on large sequences

3:49 amalloy: no

3:49 join is just implemented as a call to apply str. how else could it work?

3:49 alexyakushev: Sure about that? :D

3:50 amalloy: ~def clojure.string/join

3:50 alexyakushev: Ah, OK, I see now

3:50 No-separator version is just apply str

3:50 I accept my defeat

3:51 amalloy: and of course the body of str looks like the with-separator version of join

3:54 alexyakushev: Still, if join was implemented with explicit loop, it could be faster than apply, right?

3:55 amalloy: no

3:55 apply str *is* implemented with the explicit loop you are talking about

3:57 alexyakushev: I'm kinda confused with this `spread` thing

3:58 amalloy: spread is just apply list

3:58 but it's implemented before apply exists, in order to implement apply

4:07 alexyakushev: The world I've been living in crumbles, what you gonna do

4:07 Thanks for the revelations

4:08 I also found out that `reduce str` is much slower than `apply str`. Now I understand why is that, but before I would never think apply is sometimes faster than reduce

4:12 amalloy: alexyakushev: generally if apply and reduce do the same thing for a particular function, apply will always be at least as fast

4:13 because apply can just delegate to reduce, but the opposite is not true

4:14 and it's often faster, because as you can see in the case of str, it can perform "global" optimizations that aren't available from the keyhole perspective of reduce

4:18 mmeix: so (apply + ...) would be preferable to (reduce + ...) in all cases?

4:19 (for this one function '+', of course)

4:19 ?

4:21 alexyakushev: Multiarity + is implemented via reduce

4:23 amalloy: well. it turns out the question is more complicatd, with transducers and reducers, because reduce can actually act on things which aren't really sequences anymore

4:24 my advice is to not actually worry about which one you use

4:24 mmeix: so if in doubt decide for readability/understandability

4:25 ad hoc question - re naming: what would be preferable: :stemup :stemUp :stem-up?

4:26 stylewise

4:26 (with the other one being :stemdown ...)

4:26 amalloy: the -

4:27 mmeix: thanks

4:27 (thought so)

5:10 kaffeeboehnchen: Hi. So i have core.clj (with the namespace test.core) and something.clj (namespace test.something). Now I want to use a function of that namespace (something/run-this). As far as I understood I have to require (ns … (:require something)) and it will load my file. How can I access the function then?

5:15 scottj: kaffeeboehnchen: you require test.something not something.

5:15 kaffeeboehnchen: test.something/run-this if you just have that basic require

5:16 TEttinger: :as can be used to make the name shorter

5:16 ,(require '[clojure.string :as cs])

5:16 clojurebot: nil

5:16 scottj: kaffeeboehnchen: and :refer [run-this] so you can just refer to run-this

5:16 TEttinger: ,(cs/replace "hey guys" #" " ", all you ladies and ")

5:16 kaffeeboehnchen: ah, yeah, sorry, I have [test.something :as something] already.

5:16 clojurebot: "hey, all you ladies and guys"

5:17 kaffeeboehnchen: (it says "no such var run-this" by the way)

5:18 *something/run-this

5:18 hm

5:20 this is my code: https://paste.xinu.at/m-Vpp/

5:21 scottj: kaffeeboehnchen: in run-test, are you sure you want ((create-db).. not (create-db)...?

5:22 (not re your problem)

5:22 kaffeeboehnchen: scottj: Well, that fixed my problem. I thougt I was importing it wrong :D

5:22 Thanks!

5:23 scottj: kaffeeboehnchen: maybe there was a compile error you didn't see

5:37 mmeix: I have a function, which works, but my beginner's gut tells me, this could be made simpler/conciser: https://www.refheap.com/102147

5:38 (ah, didn't try reduce ... never mind)

5:39 TEttinger: hmmm

5:51 mmeix:

5:51 ,(apply merge-with vector (map hash-map (map :pos c) (map :step c)))

5:51 clojurebot: {:s1 [1 5], :s2 2}

5:52 TEttinger: that was fun, is it accurate?

5:52 (I defined c in a privmsg to clojurebot)

5:53 mmeix: yes, this is quite similar with what I've found in the meantime:

5:53 ,(let [c [{:step 1, :pos :s1}

5:53 {:step 2, :pos :s2}

5:53 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

5:53 mmeix: {:step 5, :pos :s1}]]

5:53 (->> (map #(hash-map (:pos %) (:step %)) c)

5:53 (apply merge-with vector)))

5:54 umpf

5:54 TEttinger: heh

5:54 * mmeix ,(->> (map #(hash-map (:pos %) (:step %)) c) (apply merge-with vector))

5:54 mmeix: ,(->> (map #(hash-map (:pos %) (:step %)) c) (apply merge-with vector))

5:54 clojurebot: {:s1 [1 5], :s2 2}

5:55 mmeix: ah!

5:55 TEttinger: nice!

5:55 mmeix: now if I wanted every val to be a vector?

5:59 {:s1 [1 5], :s2 [2] }

5:59 TEttinger: ,(apply merge-with #(into [] %&) (map hash-map (map :pos c) (map :step c)))

5:59 clojurebot: {:s1 [1 5], :s2 2}

5:59 TEttinger: hm

6:01 mmeix: ah!

6:01 ,(->> (map #(hash-map (:pos %) [(:step %)]) c)

6:01 (apply merge-with into))

6:01 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

6:01 mmeix: urx

6:01 , (->> (map #(hash-map (:pos %) [(:step %)]) c) (apply merge-with into)))

6:01 clojurebot: #error {\n :cause "Unable to resolve symbol: c in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: c in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6543]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: c in this context"\n ...

6:02 mmeix: ,(let [c [{:step 1, :pos :s1} {:step 2, :pos :s2} {:step 5, :pos :s1}]] (->> (map #(hash-map (:pos %) [(:step %)]) c) (apply merge-with into)))

6:02 clojurebot: {:s1 [1 5], :s2 [2]}

6:02 mmeix: bingo

6:03 just learned a lesson: make every element the same shape

6:03 before into'ing

6:04 (does clojurebot garbage collect defs?)

6:05 TEttinger: yes

6:05 mmeix: so c vanished after a short time - nice!

6:05 TEttinger: ,(def c [{:step 1, :pos :s1} {:step 2, :pos :s2} {:step 5, :pos :s1}])

6:05 clojurebot: #'sandbox/c

6:05 TEttinger: ,(->> (map #(hash-map (:pos %) [(:step %)]) c) (apply merge-with into)))

6:05 clojurebot: {:s1 [1 5], :s2 [2]}

6:05 mmeix: great

6:06 thanks for brain storming!

6:09 TEttinger: yeah, glad to help!

6:10 mmeix: the Clojure mindset is growing :)

6:10 TEttinger: it's a fun break from the macro madness I've been dealing with trying to "reinvent" the fn special form for my clojuresque language that compiles to lua

6:10 mmeix: wow!

6:10 TEttinger: (hilariously, the hardest bug would never have happened in clojure, since I was missing a return statement)

6:11 mmeix: is Lua something to be interested in?

6:11 TEttinger: so it was going past the part where it evaluated the macro (correctly), and into a different section where it tries to use it as a normal function call :)

6:11 mmeix: brain twisting ...

6:12 TEttinger: I'm not sure. LuaJIT is absolutely amazing as far as dynamic language compilers go

6:12 I've been taking a functional programming lib for Lua and making it... more clojurey.

6:12 https://github.com/rtsisyk/luafun

6:12 I added reductions and made a correct partition

6:13 (before there was a function called partition that I think has a different name in clojure, and it isn't a very useful one. it's (fn [f coll] [(filter f coll) (remove f coll)]) )

6:14 mmeix: quite a undertaking! (to much for a beginner's mind :-)

6:14 justin_smith: TEttinger: that's like an anemic group-by

6:14 TEttinger: all of this has been great fun

6:14 mmeix: I can imagine that

6:16 could that become: (fn [f coll] ((juxt filter remove) f coll)) ?

6:17 (I do have a love affair with juxt since yesterday)

6:17 :D

6:17 TEttinger: yep!

6:18 justin_smith: mmeix: ##((juxt #(% true) #(% false)) (group-by even? (range 10)))

6:18 lazybot: ⇒ [[0 2 4 6 8] [1 3 5 7 9]]

6:18 justin_smith: it's better because it only walks once (but worse because not lazy)

6:18 oddcully: ,(map (just :pos :step) c)

6:18 clojurebot: #error {\n :cause "Unable to resolve symbol: just in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: just in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6543]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: just in this co...

6:19 oddcully: just that is... brain was typing and reading stuff from ju[sx]tin

6:19 TEttinger: oddcully with the long distance pass!

6:35 oddcully: mmeix: if you want to just get rid of the (:x %) calls there you could also use destructuring (fn [{:keys [step pos]}] {step pos})

6:35 mmeix: after trying, I see the elegance of (juxt :pos :step), but I'm not sure, what this buys me ...

6:35 but I have to refill to maps and then merge-with ...

6:37 right now it is a two-liner:

6:37 (fn [c] (->> (map #(hash-map (:pos %) [(:step %)]) c) (apply merge-with into)))

6:37 but destructuring - yes!

6:37 trying more variations ...

6:39 oddcully: destructing won't help the golfing. i just find it easier to read

6:40 mmeix: (no aspiring for golfing, just a concise form)

6:40 (and learning, of course)

6:44 oddcully: and there is select-keys

6:45 justin_smith: ,(select-keys (group-by even? (range 10)) [true false])

6:45 clojurebot: {true [0 2 4 6 8], false [1 3 5 7 9]}

6:54 mmeix: two new versions:

6:54 https://www.refheap.com/102152

6:54 pondering, which one I like more ...

6:56 jtmarmon_: can anyone give me a hand writing this macro? i'm trying to get this sucker to work: https://gist.github.com/jtmarmon/5980c80ea98cc8cc2b59 . the problem with the one on top is that it won't work if the 3rd item in the let clause is nil.

6:59 mmeix: (scratch that, of course: https://www.refheap.com/102153)

7:14 justin_smith: ,(apply zipmap ((juxt (comp list :pos) (comp list vector :step)) {:step 1, :pos :s1}))

7:14 clojurebot: {:s1 [1]}

7:15 mmeix: ah ...

7:15 justin_smith: point-free, heh

7:18 mmeix: elegant! just trying ... has to work on a coll like [{:step 1, :pos :s1} {:step 2, :pos :s2}]

7:18 justin_smith: right, you would map it

7:19 ,(map (partial apply zipmap ((juxt (comp list :pos) (comp list vector :step))) [{:step 1, :pos :s1} {:step 2 :pos :s2}]))

7:19 clojurebot: #error {\n :cause "Wrong number of args passed to keyword: :pos"\n :via\n [{:type java.lang.IllegalArgumentException\n :message "Wrong number of args passed to keyword: :pos"\n :at [clojure.lang.Keyword throwArity "Keyword.java" 97]}]\n :trace\n [[clojure.lang.Keyword throwArity "Keyword.java" 97]\n [clojure.lang.Keyword invoke "Keyword.java" 110]\n [clojure.core$comp$fn__4493 invoke "core.c...

7:19 justin_smith: err

7:19 ,(map (partial apply zipmap (partial (juxt (comp list :pos) (comp list vector :step))) [{:step 1, :pos :s1} {:step 2 :pos :s2}]))

7:19 clojurebot: #object[clojure.core$map$fn__4547 0x33a58260 "clojure.core$map$fn__4547@33a58260"]

7:20 justin_smith: err...

7:20 something like this, I probably should go back to sleep

7:31 mmeix: lots of options!

7:34 justin_smith: ,(map (comp (partial apply zipmap) (partial (juxt (comp vector :pos) (comp vector vector :step)))) [{:step 1, :pos :s1} {:step 2 :pos :s2}])

7:34 clojurebot: ({:s1 [1]} {:s2 [2]})

7:34 justin_smith: point free starts to get kind of silly

7:36 ,(map (comp (partial apply zipmap) (juxt (comp list :pos) (comp list vector :step))) [{:step 1, :pos :s1} {:step 2 :pos :s2}])

7:36 clojurebot: ({:s1 [1]} {:s2 [2]})

7:42 TEttinger: nice try, justin_smith

7:43 justin_smith: ,(map (comp (partial apply hash-map) (juxt :pos (comp vector :step))) [{:step 1, :pos :s1} {:step 2 :pos :s2}])

7:43 clojurebot: ({:s1 [1]} {:s2 [2]})

7:44 TEttinger: ,(def c [{:step 1, :pos :s1} {:step 2, :pos :s2} {:step 5, :pos :s1}])

7:44 clojurebot: #'sandbox/c

7:46 justin_smith: ,(apply merge-with into (map (comp (partial apply hahs-map) (juxt :pos (comp vector :step))) c))

7:46 clojurebot: #error {\n :cause "Unable to resolve symbol: hahs-map in this context"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unable to resolve symbol: hahs-map in this context, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6543]}\n {:type java.lang.RuntimeException\n :message "Unable to resolve symbol: hahs-ma...

7:46 TEttinger: hah

7:46 justin_smith: ,(apply merge-with into (map (comp (partial apply hash-map) (juxt :pos (comp vector :step))) c))

7:46 clojurebot: {:s1 [1 5], :s2 [2]}

7:46 TEttinger: hahsmap

7:46 there we go!

7:46 justin_smith: point-free is crazy

7:46 TEttinger: what is point-free?

7:47 no definitions?

7:47 justin_smith: TEttinger: no named bindings

7:47 TEttinger: ah

7:47 justin_smith: where % also counts as a name

7:47 TEttinger: is %& a named binding?

7:47 justin_smith: yes

7:47 it's a name, you can position it arbitrarily in a form

7:47 TEttinger: how would you do varargs in point-free

7:47 err

7:47 can you?

7:48 justin_smith: TEttinger: sure, apply

7:48 TEttinger: oh nvm

7:48 justin_smith: well, apply explits existing varargs

7:48 TEttinger: ,(defn [& args other] (apply str other args))

7:48 clojurebot: #error {\n :cause "First argument to defn must be a symbol"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.IllegalArgumentException: First argument to defn must be a symbol, compiling:(NO_SOURCE_FILE:0:0)"\n :at [clojure.lang.Compiler macroexpand1 "Compiler.java" 6644]}\n {:type java.lang.IllegalArgumentException\n :message "First argument to defn must be a s...

7:48 TEttinger: ,(defn guh [& args other] (apply str other args))

7:48 clojurebot: #error {\n :cause "Unexpected parameter"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: Unexpected parameter, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6740]}\n {:type java.lang.RuntimeException\n :message "Unexpected parameter"\n :at [clojure.lang.Util runtimeException "Util.java" 221]}]\n :tr...

7:49 justin_smith: TEttinger: do you mean [other & args] ?

7:49 TEttinger: <justin_smith> it's a name, you can position it arbitrarily in a form

7:49 that was what I was testing

7:49 justin_smith: TEttinger: not the binding vector

7:49 the binding you create

7:49 TEttinger: it's still a form, the binding vector!

7:50 justin_smith: TEttinger: yes, in [& args] args is a binding, because you can use args anywhere in the following form

7:50 TEttinger: good ol' sleeping pills making me trollishly pedantic

7:50 justin_smith: I was not meaning to imply you can rearrange the binding vector itself, that's just silly

7:50 haha

7:51 mmeix: madstructuring, so to say :D

7:51 (mmeix returns to listening & learning)

7:52 justin_smith: TEttinger: anyway, if you have a binding form of any sort, you definitely aren't point-free

7:52 TEttinger: ah!

7:53 justin_smith: let me see if I can recall all the ingredients needed for point-free in clojure...

7:53 TEttinger: ,(partial + (map inc (range 5)))

7:53 clojurebot: #object[clojure.core$partial$fn__4525 0xad60240 "clojure.core$partial$fn__4525@ad60240"]

7:53 justin_smith: juxt, comp, partial, apply

7:53 TEttinger: ((partial + (map inc (range 5))) (range 10 20))

7:53 justin_smith: sadly we don't have flip

7:53 TEttinger: ,((partial + (map inc (range 5))) (range 10 20))

7:53 clojurebot: #error {\n :cause "clojure.lang.LazySeq cannot be cast to java.lang.Number"\n :via\n [{:type java.lang.ClassCastException\n :message "clojure.lang.LazySeq cannot be cast to java.lang.Number"\n :at [clojure.lang.Numbers add "Numbers.java" 128]}]\n :trace\n [[clojure.lang.Numbers add "Numbers.java" 128]\n [clojure.core$_PLUS_ invoke "core.clj" 955]\n [clojure.core$partial$fn__4525 invoke "core...

7:53 justin_smith: I think you need apply there

7:54 TEttinger: how would you get the partial to take 1 of 2 seq arguments?

7:54 map can take any number of seqs

7:54 what if you want a partial that only has one of them supplied

7:55 justin_smith: ,((partial map + (map inc (range 5))) (range 10 20))

7:55 clojurebot: (11 13 15 17 19)

7:55 TEttinger: oh herp

7:55 (inc justin_smith) ; a thousand times again

7:55 lazybot: ⇒ 260

7:56 mmeix: is point-free-ness something to strive for, besides elegance?

7:56 justin_smith: ,((partial map + (map inc (range 5))) (range 10 20) (range 420 42))

7:56 clojurebot: ()

7:56 TEttinger: mmeix, oh ni

7:56 no

7:56 justin_smith: ,((partial map + (map inc (range 5))) (range 10 20) (range 42 420))

7:56 clojurebot: (53 56 59 62 65)

7:56 TEttinger: it impairs readability IMO

7:56 justin_smith: mmeix: it's considered a style to strive for in haskell

7:56 TEttinger: programming is about assigning good names to complex things

7:56 justin_smith: but without currying it makes much less sense

7:57 and even with currying people find it baffling

7:57 mmeix: but it is good training :-)

7:57 something I wanted to ask yesterday: do let-bindings bring a performance penalty with them?

7:57 justin_smith: it's a good thought exercise, I find

7:58 mmeix: not noticible ones, no

7:58 mmeix: or a memory

7:58 penalty

7:58 justin_smith: clojure does locals clearing

7:58 so not usually an issue

7:58 mmeix: so they get garbage collected early

7:58 justin_smith: mmeix: if the compiler can know they can't escape scope, yes

7:59 mmeix: ah, sounds logical

7:59 justin_smith: but the compiler is intentionally a bit daft

7:59 we don't try to make the compiler super clever, unlike most mainstream languages

8:00 mmeix: how does this look in clojurescript? would I strive for memory/speed in this way? (thinking tablets etc.)

8:03 I always thougt, "partial" is currying ...

8:11 stain: more (partial)?

8:12 mmeix: ?

8:12 stain: ah, it's a different discussion. it was discussed earlier in the week, lambda vs partial

8:13 mmeix: no, the context here was point-free functions, and their usefulness/...

8:14 if I got that right :)

8:18 stain: ah

8:18 mmeix: Justin wrote a solution for a function I tried

8:18 stain: lazy sequences are kind of also in the same field.. but that's more with performance than with doing a pipeline style

8:19 in my never-available time I try to write a workflow language for composing clojure functions, where you just state the connections

8:19 TEttinger: nice, stain

8:20 mmeix: that sounds interesting

8:20 stain: it's not very different from working with futures

8:20 except that I want it to be push rather than pull

8:24 mmeix: would this resemble a glorified threading macro?

8:25 (sorry, glorified is not a proper word maybe, bear with non native speakers ...)

8:25 stain: (defstep dostuff [a b] (str a b)) (defstep otherstuff [c] (str "x" c)) (link dostuff otherstuff :c) (link "fred" dostuff :a) (link "soup" dostuff :b) (println (deref otherstuff))

8:25 something like that.. just independent connections from outputs to parameters

8:25 obviously you can link the same output to multiple destinations

8:26 mmeix: reminds me of old school Moog Synthesizers :D

8:26 stain: but not so easily the other way around

8:26 mmeix: in studio language the use fan-in and fan-out for that

8:27 stain: yeah, I've worked on a workflow system called Apache Taverna, and there we have lots of magic like if there's multiple links to an input port/parameter, they are merged into a wrapping list

8:27 mmeix: multiple inputs would need a standard "summing" function, I guess

8:27 stain: and if you give a list to somethign that expects a value, autoamtic (map)

8:27 mmeix: ah!

8:27 stain: but that's a bit trickier in Clojure where generally parameters don't have a defined list depth

8:27 but perhaps my defstep could allow that

8:28 it would mean a more complex workflow compilation which can't be done before the whole workflow is defined

8:28 mmeix: exciting!

8:29 needs a HyperREPL

8:29 stain: really I am just looking at a way to throw out our existing Taverna workflow engine and translate to Clojure code

8:29 as then it could basically be compiled down to run directly on the JVM.. currently it runs in kind of "interpreted" mode

8:30 e.g. the code for running a step will push out the values downstream, which then sees if the other values have arrived, which then execute and push furthe retc

8:30 mmeix: I could use something like that for my music project

8:30 stain: mmeix: so then you would have basically an endless stream of signals, right?

8:31 mmeix: right

8:31 stain: it sounds like you would need a clock-based workflow

8:31 mmeix: not necessarily

8:31 it could produce several related versions of something

8:32 reminds me a bit of http://en.wikipedia.org/wiki/Max_(software)

8:32 stain: let's say left-hand side of your workflow takes much longer time than right-hand side, and the last step is say to mix them, will you wait for the whole thing to finish a clock cycle before merging their signals, or just merge them at best effort and just hope the delays are not too bad?

8:33 depends if you want digital or analog synth in a way :)

8:33 mmeix: yes

8:33 stain: in analog you would appreciate those kind of aritfacts

8:33 mmeix: some signals could be Audio related

8:33 some would carry semantic data

8:34 or notation

8:34 example: https://cycling74.com/2013/01/24/bach-beta-0-7-release/

8:36 Web Audio has a similar concept

8:36 stain: cool stuff

8:36 mmeix: yes ... the MAX people are around for a long time now

8:37 this is coming from developments in Paris IRCAM initally

8:37 and Clojure lends itself to those concepts

8:37 this is, why I'm learning it now

8:38 there is a very long tradition of using LISPs in music generation

8:38 decades, in fact

8:38 it makes sense: musical data is a stream of values, and lists

8:39 :D

8:39 stain: someone used Taverna workflows to compose music as well: http://www.taverna.org.uk/introduction/taverna-in-use/arts/composition-of-music/

8:39 mmeix: ah, thanks for the link!

8:39 stain: so what I am hoping with my workflow thing is to make it possible to define such workflows in Clojure, open them in Taverna to see them graphically and do some rewiring, and then run them again in Clojure

8:40 but that's a bit of a long shot

8:40 mmeix: let me know of the project! or can I follow you somewhere?

8:40 stain: as I don't have time to replicate the more powerful workflow engine features (e.g. automatic retries on failures)

8:40 uhm.. it's.. mainly in my head!

8:40 I'm on the twitter @soilandreyes

8:40 mmeix: np

8:40 stain: you've inspired me to have a go :)

8:41 mmeix: we live in excitig times, I find

8:41 stain: too many ideas, too little time

8:41 mmeix: yes, same here

8:41 just now coming to grips with Clojure while programming a web based music notation lib

8:42 with thinking about implementing musical semantics on a deeper level

8:43 so lot of ideas too :-)

8:43 sobel: seems like this discussion might be incomplete without mentioning Overtone

8:43 mmeix: Yes, O know Overtone

8:43 I

8:43 the synthesis side of it is great, the underlying musical semantics a bit to naive, I find

8:43 sobel: agreed

8:44 i looked straight at building instruments and puked at the amount of work left to the music developer

8:44 mmeix: musical semantics go through many levels

8:44 the MIDI-centered view is not expressive enough

8:45 sobel: i wasn't looking for a combined music+tooling learning curve at the time and it went fully technical on music, of course

8:45 mmeix: Clojure can do better, I think

8:45 yes

8:45 kaffeeboehnchen: Anyone has an idea how I can create a foreign key with java.jdbc?

8:45 sobel: agreed again on MIDI-centric being a poor model

8:45 mmeix: MIDI was invented for making another synth play

8:45 so it has really very little meaning

8:45 sobel: right. in a pretty generic sense.

8:46 worse, it assumes stateful controllers and a bunch of other crud

8:46 mmeix: musical structure is a very deep thing

8:46 sobel: :)

8:46 talk to me

8:46 mmeix: as I can confirm

8:47 (I'm teaching music theory in Vienna University for music)

8:47 sobel: excellent

8:47 mmeix: yeah, and very happy to have found Clojure as a medium to work in

8:47 now leraning frantically

8:47 as the people here can attest ;-)

8:48 lots of beginner's questions from my side

8:48 sobel: i'm still learning my way around some new tools. i used to be a regular sax player but now i am mostly an avid electronica and classical listener.

8:48 mmeix: great!

8:49 sobel: Clojure being the more familiar part. I have Ableton/MAX but I'm sortakinda not a GUI person anymore. It's horrible but I'm more productive at the CLI.

8:49 mmeix: why not?

8:49 sobel: downside is i still suck at it and the tooling isn't polished like Ableton so, lotsa pitfalls

8:50 mmeix: yes ...

8:50 sobel: why am i not a GUI person anymore? probably broken by years of software eng

8:50 mmeix: LOL

8:50 but thinking in functions is very similar to thinking music

8:50 sobel: that is, exposure to crummy GUIs starting in the early 90s continually pushed me toward traditional unix tools which were mature, if utterly lacking in GUI

8:51 mmeix: ja, they are ugly often

8:51 we will change that :-)

8:51 when I have my music notetion engine running, I'll dive deep into semantics

8:51 hopefully this summer

8:52 *notation

8:52 sobel: oh yeah, well, brief history of my programming life: i've always been a bit of a functional thinker, but i barely studied CS academically, and got distracted by OO through the early 2000s. i quit that when i figured out Lisps are the functional language for me.

8:52 mmeix: you are a professional programmer?

8:52 sobel: yes

8:52 mmeix: oh, great

8:53 I envy the pros a bit right now

8:53 but everything can be learned

8:53 sobel: yeahwell, we all envy each other for opportunities not taken ;) i try to turn that envy into collaboration because man, i did not live enough lifetimes to master all the topics and skills i can orchestrate in practice

8:54 hell, i envied pros when i was right around 10 years experienced, and thinking, geeze, does this ever get easy? where's the top of this mountoin, such that i'll be able to see a lot farther once i get to it?

8:55 and i'm sure someone at 5 years was thinking, i wish i could sql and java like sobel. not a hobby for the impatient. :)

8:55 mmeix: computer technology seems to evolve very fast - but on the other side the return of LISPs from decades ago gives some hope

8:55 for me

8:56 so it's learning and learning

8:56 I like this, OTOH

8:56 sobel: when the discipline was identified as a new science it got a lot of core research. imo, it's not surprising that so much amazing stuff was discovered and forgotten quickly.

8:57 mmeix: back to the fathers!

8:57 (same as back to JSBach :-)

8:58 and Rich is a musician too, I learned ...

8:58 sobel: disappointing, though, that we don't have better theoretical analysis tools for evaluating syntax and other language properties. oh wait, we do, and that analysis is pretty damn hard. and people went against it on purpose to create things like Java, with full knowledge they were breaking things experts relied on.

8:58 when i was a band student, most the programmers i knew were marching on the field with me every morning

8:59 mmeix: :-)

8:59 sobel: the rest dropped out of band in 9th grade. music/CS seem to be a really common combo, probably for the synergy.

8:59 or maybe it's due to the whole deal with musicians growing denser dendrite networks

9:00 mmeix: I heard a talk lately, which showed that the whole brain is exercised in musical activity

9:00 sobel: i think what i'd ideally like, is to be able to cram patterns into Ableton from a clojure repl

9:00 mmeix: I guess, we wouldnt need Ableton for that, but it should be possible ...

9:01 sobel: mmeix: oh, i think i may have seen that one cross my screen but didn't watch it. consciousness being an emergence of harmonies and other patterns in brain waves

9:01 mmeix: i'd like to express patterns with dynamics in closed form at the REPL

9:02 mmeix: one could try OSC as a intermedita medium, I guess

9:02 sobel: instead of clicking them out or playing them in, then changing over to the controller view to draw the dynamic, etc

9:02 mmeix: I'm not sure, if Ableton supports OSC

9:02 OSC is much richer than MIDI

9:02 sobel: there's a MIDIOsc server

9:02 mmeix: will think about that

9:02 ah, ok

9:02 OSC is simple text

9:03 sobel: dunno if it would meet the need but i used it to integrate a silly ipad app to ableton once

9:03 mmeix: so should totally be doable with Clojure as generator

9:03 I used LEMUR for that

9:03 great stuff

9:03 more ideas for the summer :D

9:04 sobel: does LEMUR come with an app that makes midi from the LEMUR messages?

9:04 mmeix: ja

9:04 there's a the usual desktop server app

9:04 and LEMUR in itself has a rich scripting language

9:05 https://liine.net/en/products/lemur/

9:05 sobel: oh, this is random, but.. i need to debounce midi messages from a WX-11 (wind controller) that produces a lot of spurious intermediate notes at note transitions.

9:05 mmeix: should be easily doable in MAX

9:06 there is a throttling module

9:06 sobel: it yields them at an insane rate when the switches transition, so a change involving 5 buttons can yield quite a range of shit

9:06 mmeix: I forgot

9:06 sobel: oh cool

9:06 i usually don't end up on the max side (bad at GUIs!)

9:08 mmeix: https://docs.cycling74.com/max5/refpages/max-ref/speedlim.html

9:09 I guess this could do what you want

9:09 GUI-wise: three or four nodes to click together

9:10 shouldn't be that bad

9:10 sobel: hmm. i don't want a rate limiter, i want to throw away the ones that are too fast.

9:10 mmeix: "Sets an initial minimum time between outputs. Time can be specified in any of the time formats used in Max. If there is no argument, the minimum time is 0 milliseconds."

9:10 sobel: so necessarily a slight delay

9:11 mmeix: if it's less than 20 ms or so, one woldn't perceive it, I guess

9:11 and MIDI isn't that fast anyway :-)

9:11 sobel: not real MIDI

9:12 mmeix: there is an example on the bottom of the page, where they limit pitchbends

9:13 sobel: IIRC oh dear, the original spec was 3.125Kbps. i got on board when it was routinely run over 100k, ISTR.

9:14 mmeix: I have to leave, but hopefully we meet again here ... I'll be online a lot with pestering the pros with beginner's questions (ask justin_smith :-)

9:15 sobel: i bother justin_smith occasionally as well :) i'm around on and off throughout the year. be well!

9:15 mmeix: you too!

10:14 what is common wisdom re default values for defrecord?

10:14 I'm reading here: http://cemerick.com/2010/08/02/defrecord-slot-defaults/

10:14 he does a macro for this

10:15 the article is from 2010 though, so maybe there is some common practice now?

10:16 crocket: Do clojurists use try/catch often?

10:16 In java, I did.

10:16 Checked exceptions were evil.

10:20 kaffeeboehnchen: Is there any way to use google groups without google id? I wanted to ask something on the java.jdbc group :(

10:20 oddcully: mmeix: the way i do it is with a new-something method, that calls map->Something where i merge defaults

10:21 mmeix: I just found this article: http://stuartsierra.com/2015/05/17/clojure-record-constructors

10:22 thanks! this makes sense ...

10:41 so this would be a simple form of a constructor:

10:41 (defn pitch [step & accidental] (map->Pitch {:step step :accidental :none}))

10:41 clojury?

10:49 TimMc: kaffeeboehnchen: I think you have to create a Google account, but you can have it go to your real email.

11:05 oddcully: mmeix: where is your accidental used?

11:08 mmeix: some note have accidentals, other not

11:08 pitch would be part of a chord [pitch1 pitch2 pitch3]

11:09 chord would be part of a graphical unit

11:09 [chord stem flag dots]

11:10 this unit has to do a lot of calculations to place symbols where they belong

11:10 for example a function which cares for accidental placement

11:10 and so on

11:11 Would it be better to omit :accidental :none ?

11:13 so the accidental machinery would collect all pitches and build a stem with noteheads out of it, and a stack of accidentals, which go left of the notehead/stem/flag-combo

11:14 this is the use case

11:15 but if I do (defrecord Pitch [step accidental]) I'm obliged to supply a value for both, right?

11:16 ,(defrecord Pitch [:step :accidental])

11:16 clojurebot: #error {\n :cause "defrecord and deftype fields must be symbols, sandbox.Pitch had: :step, :accidental"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.AssertionError: defrecord and deftype fields must be symbols, sandbox.Pitch had: :step, :accidental, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.core$validate_fields invoke "core_deftype.clj" 292]}\n {:type ja...

11:17 mmeix: err

11:17 ,(defrecord Pitch [step accidental])

11:17 clojurebot: sandbox.Pitch

11:19 mmeix: ,(def n1 (->Pitch 7)

11:19 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

11:19 mmeix: ,(def n1 (->Pitch 7))

11:19 clojurebot: #error {\n :cause "Wrong number of args (1) passed to: sandbox/eval48/->Pitch--63"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "clojure.lang.ArityException: Wrong number of args (1) passed to: sandbox/eval48/->Pitch--63, compiling:(NO_SOURCE_FILE:0:0)"\n :at [clojure.lang.Compiler$InvokeExpr eval "Compiler.java" 3628]}\n {:type clojure.lang.ArityException\n :message ...

11:20 mmeix: ,(defn pitch [step & acc] (map->Pitch {:step step :acc :none}))

11:20 clojurebot: #'sandbox/pitch

11:21 mmeix: ,(def n1 (pitch 7))

11:21 clojurebot: #'sandbox/n1

11:21 mmeix: ,(def n2 (pitch 4 :sharp))

11:21 clojurebot: #'sandbox/n2

11:22 mmeix: (sorry for generating unnecessary error stacks)

11:23 ,(def chord [n1 n2])

11:23 clojurebot: #'sandbox/chord

11:23 borkdude: for anyone interested in migration a project from leiningen to boot, first steps: http://blog.michielborkent.nl/blog/2015/06/06/from-leiningen-to-boot/

11:23 mmeix: ,(map :step chord)

11:23 clojurebot: (7 4)

11:23 oddcully: i ask because of step & acc and then acc never beeing used

11:23 mmeix: ,(map :acc chord)

11:23 clojurebot: (:none :none)

11:24 mmeix: ah - silly me

11:24 ok

11:28 mr_rm: does anyone know if it's possible to make vsclojure NOT separate the '.' from a property or method name when it reformats the document with ctrl-E,D?

11:28 sorry for kind of off topic but nobody talking in #vsclojure

11:29 e.g. reformatting changes (-> obj .Foo) to (-> obj . Foo) and this frequently causes errors

11:43 ok different question... does anyone think Clojure on .Net will ever be anything other than a novelty? I love Clojure/JVM and use it all the, and Clojurescript seems to get a lot of mindshare, but the .Net world is... different. I'm just really wondering if looking there is even worth the time. Could be learning F# instead

12:14 hadronzoo: With reader conditionals, is it now possible to define and use macros within the same cljc file when targetting clojurescript?

12:21 Ah, just figured it out using #?(:cljs (:require-macros [current-ns]))

12:46 dhardison: i'm working on an app and i'm trying to understand the scope of a variable i've defined using (def active-piece -1). I want to update the value inside a block of code -- should i be using def or let?

12:47 wasamasa: let establishes local bindings shadowing outer bindings

12:48 dhardison: so i should just use def -- correct?

12:48 gfredericks: dhardison: def isn't designed for mutation

12:48 dhardison: for this case at least

12:48 wasamasa: def would work, but isn't ideal

12:48 dhardison: ah - hmmm well is there a way i can have a global mutable value

12:48 gfredericks: ideally you would figure out a way to not have one

12:48 dhardison: i'm trying to keep it simple for now

12:48 gfredericks: but if you really want one

12:48 dhardison: while i figure all this out.

12:49 gfredericks: ,(def active-piece (atom -1))

12:49 clojurebot: #'sandbox/active-piece

12:49 gfredericks: ,(swap! active-piece + 10)

12:49 clojurebot: 9

12:49 gfredericks: ,(swap! active-piece + 10)

12:49 clojurebot: 19

12:49 gfredericks: ,(swap! active-piece inc)

12:49 clojurebot: 20

12:49 gfredericks: ,(reset! active-piece 9000)

12:49 clojurebot: 9000

12:49 gfredericks: ,(deref active-piece)

12:49 clojurebot: 9000

12:50 gfredericks: also http://clojure.org/state

12:50 dhardison: gotcha, thank you very much

12:51 Jickelsen: ,(go (let [foo (<!

12:51 (#(let [c (chan)] (>! c "bar") c))

12:51 )]

12:51 foo))

12:51 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

12:53 Jickelsen: Returns #<[Object Object]>

12:53 nil

12:53 for me

12:54 gfredericks: is it a channel?

12:54 go always returns a channel

12:54 justin_smith: Jickelsen: has to be on one line, clojurebot does not do multi line input

12:54 Jickelsen: and clojure bot does not do core.async :P

12:54 gfredericks: and clojure bot only evaluates haskell

12:54 Jickelsen: I suspect it could lead to a whole lot of shenanigans!

12:55 gfredericks: and clojure bot does not exist

12:55 and we are all different slices of a very finely sliced pumpkin pie

12:56 * gfredericks not sure how he got to this point

13:02 Jickelsen: I tried switching out foo for a global atom

13:02 (go (reset! foo (<!

13:02 (#(let [c (chan)] (>! c "bar") c))

13:02 )) but the value of foo has not been changed

13:02 Also I forgot to paste in a closing parenthesis, sorry

13:02 justin_smith: Jickelsen: go returns a channel

13:03 gfredericks: justin_smith: which is the point of switching to an atom

13:03 justin_smith: and your block inside also puts a channel into c

13:04 gfredericks: ahh, OK

13:04 and what's the point of (#(...)) instead of (...)

13:06 gfredericks: probably nothing

13:06 Jickelsen: (>! (chan) "bar") only returns true though, won't it?

13:07 justin_smith: Jickelsen: sure, but you are not using the return value of that anyway

13:07 ,(let [] 42 :a)

13:07 clojurebot: :a

13:17 Jickelsen: True! I switched to an atom since the return value of the block wasn't very helpful. Could have used a print statement though. So it seems the MVP (eeh) should have been

13:17 (go (reset! foo (<!

13:17 (let [c (chan)] (>! c "bar") c))))

13:17 The atom, however, remains unfazed

13:18 justin_smith: Jickelsen: I'm trying to remember, there may be rules about reading and writing the same channel in one block?

13:19 dhardison: what's the proper syntax to return true/false at the end of a function call?

13:19 justin_smith: dhardison: true

13:19 or maybe false

13:19 ,((fn [] (print "did something") true))

13:19 clojurebot: did somethingtrue

13:20 dhardison: justin_smith: must it happen at the end or can i do it within an if statement

13:20 Jickelsen: justin_smith: I think you're right!

13:20 justin_smith: dhardison: you can only return from the end of a function (but an if statement can change where the "end" is)

13:20 dhardison: k thanks

13:26 justin_smith: Jickelsen: https://www.refheap.com/102178

13:27 Jickelsen: I can reproduce, doing it inside one go block fails

13:29 Jickelsen: in case you loaded already, refresh, I added extra lines demonstrating that the value "foo" was still in c after, and that by putting another value in c I could make that eventually end up in result

13:30 so yeah, it's definitely the "don't read and write the same chan in one go block" rule in action

13:38 Jickelsen1: Thank you, now at least I know why my async-jousting in the repl wasn't working :)

13:39 justin_smith: I hope the stuff I was trying to demonstrate in that refheap paste is clear

13:41 like, it did read and write the same channel in one go block, but just not to / from itself at all...

13:46 mmeix: ok, there must be a better way (bare with me, as always):

13:46 ,(defrecord Simpson [name hair])

13:47 clojurebot: sandbox.Simpson

13:47 mmeix: ,(defn new-simpson [name & [hair]]

13:47 (map->Simpson {:name name :hair (or hair "blond")}))

13:47 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

13:47 dhardison: what does syntax similar to :refer or :black etc mean in clojure

13:47 mmeix: ,(defn new-simpson [name & [hair]](map->Simpson {:name name :hair (or hair "blond")}))

13:47 clojurebot: #'sandbox/new-simpson

13:48 mmeix: ,(def lisa (new-simpson "Lisa"))

13:48 clojurebot: #'sandbox/lisa

13:48 mmeix: ,(def marge (new-simpson "Marge" "blue!"))

13:48 clojurebot: #'sandbox/marge

13:48 mmeix: ,lisa

13:48 clojurebot: #sandbox.Simpson{:name "Lisa", :hair "blond"}

13:48 mmeix: ,marge

13:48 clojurebot: #sandbox.Simpson{:name "Marge", :hair "blue!"}

13:49 mmeix: this doesn't feel right for me: "[name & [hair]"

13:49 "[name & [hair]]"

13:49 just to avoid parens in the val

13:49 gfredericks: ,(defn new-simpson ([name] (new-simpson name "blond")) ([name hair] (->Simpson name hair)))

13:49 clojurebot: #'sandbox/new-simpson

13:50 mmeix: ok

13:50 thanks

13:51 gfredericks: I'd like a better syntax for default args

13:51 Jickelsen1: justin_smith: I get the gist of it, I need to read up a bit on when to use put! though

13:51 gfredericks: I don't like [name & [hair]] because you get a squishier function that accepts any 1+ args

13:52 mmeix: I tried {:keys ...}

13:52 but that feels a bit convoluted too

13:54 in a simple case of 1-3 args a variadic func is easy enough

13:54 thanks again

14:02 follow-up:

14:02 ,(defrecord Pitch [step acc])

14:02 clojurebot: sandbox.Pitch

14:02 mmeix: ,(defn pitch ([step] (pitch step nil)) ([step acc] (->Pitch step acc)))

14:02 clojurebot: #'sandbox/pitch

14:02 oddcully: mmeix: if you have many different optional params you can allow passing a map as last param, merge with your defaults and send it to map->Record

14:03 justin_smith: Jickelsen1: (put! c val) is usually the better equivalent of (go (>! c val)) - it is for async offering of a value to a channel

14:03 gfredericks: stuartsierra's latest blog post was on that topic http://stuartsierra.com/2015/06/01/clojure-donts-optional-arguments-with-varargs

14:04 mmeix: (ja, just read that article)

14:04 justin_smith: dhardison: ##(type :foo)

14:04 lazybot: ⇒ clojure.lang.Keyword

14:05 mmeix: my question was:

14:05 justin_smith: dhardison: keywords are symbols that only stand for themselves, they never get resolved directly to a binding (though they are commonly used as keys in maps by which bindings are looked up)

14:05 mmeix: would it be better to do "(defn pitch ([step] (pitch step nil)) ..."

14:05 or "(defn pitch ([step] (pitch step :none))..." ?

14:05 justin_smith: mmeix: ahh

14:06 yeah, nil is idiomatic for "none" I think

14:06 mmeix: ok

14:06 oddcully will try the merge

14:06 dhardison: justin_smith: thanks

14:06 justin_smith: it's a decent "none of the above" value, since things like or or if handle it nicely

14:07 mmeix: a good addition, if using nil for none and merging, is a function that removes keys if they have a nil value

14:07 mmeix: AHA!

14:08 (sorry for shouting.. )

14:08 justin_smith: (defn without-nil-keys [m] (into (empty m) (remove (comp nil? second) m))

14:08 gfredericks: I hate computers

14:09 justin_smith: or (merge-with #(or %2 %) m1 m2)

14:09 gfredericks: haha

14:10 gfredericks: I just made this refactor that changes things to use strictly fewer function calls and it made everything like 5% slower: https://github.com/clojure/test.check/commit/71fb1bd185025d55e10ed1cdaf1b1c64d240fc10

14:10 mmeix: (thanks for abundance of patience)

14:11 gfredericks: life is a lot easier when you don't measure how fast things go

14:11 justin_smith: gfredericks: mo' criteria mo' problems

14:12 gfredericks: which is why I only use one simple test to make all decisions

14:12 gfredericks: "is it dope?"

14:12 justin_smith: haha

14:12 dope has a complex dependency tree

14:12 coin flips are isolated :)

14:13 gfredericks: this is the OOP version of "simple"

14:13 all I have to do is call it.isDope() how could anything be simpler

14:14 anyhow so while you're all here I'm been thinking about activerecord-envy and wondering if there are things that could be done

14:15 I'm thinking specifically about solving problems of CRUD, type conversion, key spelling style conversion, and maybe other things, with minimal boilerplate and ideally no magic

14:16 justin_smith: gfredericks: this is a bunch of what Caribou was / is about, though it is not as advanced as nuanced as what you have in mind I bet

14:19 gfredericks: oh hey I haven't seen that

14:20 which lib?

14:20 carbiou-core?

14:20 justin_smith: caribou-core is the db and modeling layer

14:20 caribou-admin is the web UI for CRUD

14:20 allows point and click / drag and drop modeling

14:21 gfredericks: definitely haven't been thinking about webby stuff

14:21 justin_smith: my intro to clojure was getting hired to work on Caribou

14:22 gfredericks: how does this interact with java.jdbc

14:22 justin_smith: gfredericks: it wraps variou jdbc drivers (right now mysql, postgres, and h2 have full support)

14:23 *various

14:23 it uses an edn data structure to describe a data model, and that gets stored / retrieved as data in the db itself

14:23 gfredericks: so doesn't use java.jdbc at all? uses JDBC directly?

14:23 justin_smith: and schema changes are also reflected in the model table

14:23 the implementation uses jdbc for everything

14:24 though at one point we considered implementing datomic and mongo support, those are still vapor

14:25 borkdude: I thought if there exists a very light weight ORM library written in Java or so, that can be used from Clojure easily

14:25 gfredericks: oh man I definitely don't want an ORM

14:25 justin_smith: probably - we didn't like any of the ones we knew

14:25 we didn't want ORM - we wanted MRM (map relational modeling)

14:25 borkdude: without getting stuck with annotation, but just being able to use edn

14:26 justin_smith: borkdude: yeah, that's what we aimed for - the RM part without stateful object behavior stuff at all

14:27 borkdude: the more I thought about it, the more clojure.java.jdbc fit my needs :)

14:28 gfredericks: I'm working in a few projects that have a lot of CRUD boilerplace

14:28 with java.jdbc

14:29 and java.jdbc's protocols aren't sufficient for all the type conversion we have to do

14:31 justin_smith: gfredericks: oh, caribou wouldn't help you then - it just uses a small edn subset

14:32 gfredericks: I almost thought about making a library just for specifying conversions

14:32 types and keys

14:32 maybe prismatic/schema would be sufficient for that

14:32 or at least could be an implementation

14:33 I think using camel-snake-kebab and just blindly converting everything is pretty gross

14:34 dhardison: what's the best way to debug a clojurescript application

14:35 right now i'm compiling and running and fumbling in the dark

14:35 justin_smith: dhardison: I find figwheel helps a lot, also cljs.test works

14:35 dhardison: and definitely use the chrome inspector / console if you are not yet

14:36 it has breakpoints, stack inspection, local inspection, etc.

14:42 dhardison: justin_smith: hmm i'd love to use devtools but does it support looking into variables?

14:42 justin_smith: dhardison: in my experience yes, it shows local variables, and namespace level defs

14:42 though you do have to figure out the "munging" to get the js version of the thing you want

14:43 but that's where the figwheel repl also helps - it's a cljs repl

14:43 as opposed to the console js repl

16:00 lalops: Direct download links/forum attatchments SEO ANALYZER SCRIPT: /AMSG FREE SEO ANALYZER SCRIPT DOWNLOAD ATTATCHMENT FOUND: http://www.websiteadverts.org/forum/showthread.php?tid=17 WEBSITE WORTH CALCULATOR SCRIPT: http://www.websiteadverts.org/forum/showthread.php?tid=16

16:38 noncom: if i pass, say, a clojure {} into a java method that accepts a HashMap and the java code modifies the {}, that breaks the immutability, right?

16:38 i mean, it is no longer done through STM ?

16:39 justin_smith: noncom: how would it modify the {}

16:39 STM cannot modify {}

16:39 noncom: justin_smith: isn't {} a HashMap ?

16:39 justin_smith: ,(type {})

16:39 clojurebot: clojure.lang.PersistentArrayMap

16:39 noncom: omg

16:39 how can i be so lame..

16:39 justin_smith: ,(type (java.util.HashMap.))

16:39 clojurebot: java.util.HashMap

16:40 noncom: right, right, my daily dose of stupidity :D

16:40 uptown: i'm still on an hourly dose personally

16:40 justin_smith: noncom: on the other hand (instance? java.util.Map {})

16:40 ,(instance? java.util.Map {})

16:40 clojurebot: true

16:40 justin_smith: ,(instance? java.util.Map (java.util.HashMap.))

16:40 clojurebot: true

16:41 noncom: (.add {} 1 1)

16:41 ,(.add {} 1 1)

16:41 clojurebot: #error {\n :cause "No matching method found: add for class clojure.lang.PersistentArrayMap"\n :via\n [{:type java.lang.IllegalArgumentException\n :message "No matching method found: add for class clojure.lang.PersistentArrayMap"\n :at [clojure.lang.Reflector invokeMatchingMethod "Reflector.java" 53]}]\n :trace\n [[clojure.lang.Reflector invokeMatchingMethod "Reflector.java" 53]\n [clojure.lan...

16:41 justin_smith: ,(.add (java.util.HashMap.) 1 1)

16:41 clojurebot: #error {\n :cause "No matching method found: add for class java.util.HashMap"\n :via\n [{:type java.lang.IllegalArgumentException\n :message "No matching method found: add for class java.util.HashMap"\n :at [clojure.lang.Reflector invokeMatchingMethod "Reflector.java" 53]}]\n :trace\n [[clojure.lang.Reflector invokeMatchingMethod "Reflector.java" 53]\n [clojure.lang.Reflector invokeInstanceMe...

16:41 justin_smith: ,(.put (java.util.HashMap.) 1 1)

16:41 clojurebot: nil

16:41 noncom: ,(.put {} 1 1)

16:41 clojurebot: #error {\n :cause nil\n :via\n [{:type java.lang.UnsupportedOperationException\n :message nil\n :at [clojure.lang.APersistentMap put "APersistentMap.java" 374]}]\n :trace\n [[clojure.lang.APersistentMap put "APersistentMap.java" 374]\n [sun.reflect.NativeMethodAccessorImpl invoke0 "NativeMethodAccessorImpl.java" -2]\n [sun.reflect.NativeMethodAccessorImpl invoke "NativeMethodAccessorImpl.jav...

16:41 justin_smith: unsupported operation :)

16:41 noncom: ah, unsupported op

16:42 cool! :)

16:42 so it gives the guarantee...

16:42 justin_smith: I mean you could use reflection and get at the internals and mutate - but that's tricky, and you can break most anything in the jvm that way if determined to :)

16:43 ,(java.util.HashMap. {:a 0})

16:43 clojurebot: {:a 0}

16:44 justin_smith: ,(.get (java.util.HashMap. {:a 0}) :a)

16:44 clojurebot: 0

16:44 justin_smith: if you really need the mutable thing, that is very easy to arrange

16:45 ,(.get (doto (java.util.HashMap. {:a 0}) (.put :b 1)) :b)

16:45 clojurebot: 1

16:47 noncom: i see!

16:47 actually in this current place i am concerned with making the user unable to mutate

16:47 justin_smith: ,(into {} (doto (java.util.HashMap.) (.put :a 0) (.put :b 1)))

16:47 clojurebot: {:b 1, :a 0}

16:47 justin_smith: cool

16:48 noncom: but your last example is good to remember also when i need it

16:59 borkdude: Clojure related blog post is now in top 10 on Hacker News

17:00 justin_smith: borkdude: your post about boot?

17:00 borkdude: yeah :)

17:00 justin_smith: congrats

17:00 borkdude: tnx

17:14 dhardison: i'm running (def x (atom {:d 2})) -- and then (get x :d) and it's returning nil -- any ideas

17:14 Bronsa: ,(def x (atom {:d 42}))

17:14 dhardison: i also tried (get (deref x) :d)

17:14 Bronsa: ,x

17:14 clojurebot: #'sandbox/x

17:14 #object[clojure.lang.Atom 0x66862bb9 {:status :ready, :val {:d 42}}]

17:14 Bronsa: ,(class x)

17:14 clojurebot: clojure.lang.Atom

17:14 Bronsa: ,(class @x)

17:14 clojurebot: clojure.lang.PersistentArrayMap

17:15 Bronsa: ,(get @x :d)

17:15 clojurebot: 42

17:15 dhardison: ah

17:15 what does @ symbol do

17:15 justin_smith: ,'@x

17:15 clojurebot: (clojure.core/deref x)

17:15 Bronsa: ,`@x

17:15 clojurebot: (clojure.core/deref sandbox/x)

17:15 Bronsa: damn you justin_smith !

17:15 justin_smith: haha

17:19 noncom: dhardison: @x is a shortcut for (deref x) and it gets what is "inside" the atom. in your case, that's {:d 2}

17:20 justin_smith: and also, get works with like - anything

17:20 ,(get nil :a)

17:20 clojurebot: nil

17:20 justin_smith: ,(get Double/NaN :a)

17:20 Bronsa: ,(get 42 23 37)

17:20 clojurebot: nil

17:20 37

17:20 amalloy: dhardison: more than a specific answer to your question about @, note the general technique justin_smith just showed you: if you're not sure what some shorthand means, just put a quote in front of it and see how it expands

17:20 dhardison: i see - i was trying it out on tryclj.com but it was giving me an error

17:21 thanks amalloy

17:21 noncom: yes, get is sorta fail-safe, so you just get nil instead of a NullPointerException or something. that's often the case with clojure

17:29 thedoodPL: What is the easiest way to interact with a rest service (get and post stuff) in clojure?

17:31 is there any lib that combines clj-http and a json lib?

17:43 dhardison: so, if i dereference something from an atom, i cannot update the data directly, can i? e.g. (def x (atom {:d 1})) -- and then (assoc @x :d 2)

17:45 i'll have to do a reset!

17:51 oddcully: danlarkin: swap!

17:51 erm

17:51 dhardison: ^^

17:53 dhardison: oddcully: i'm passing in the atom into a function -- will that still work

17:53 looks like that it might be setting it to null

17:55 oddcully: ,(def a (atom {}))

17:55 clojurebot: #'sandbox/a

17:55 oddcully: ,((fn [x] (swap! x assoc :x 42)) a)

17:55 clojurebot: {:x 42}

17:55 oddcully: ,(deref a)

17:55 clojurebot: {:x 42}

17:58 dhardison: oh, i tried assoc @x :x 42 --- that's my mistake thanks

17:59 amalloy: dhardison: remember, all an atom is, is a mutable pointer to a value that, like most things in clojure, is immutable. once you derefence it, you're left with an immutable value that knows nothing about the atom it "came from"

19:09 Atlas_darkly: hello

19:24 TEttinger: ,"\u0000hey!\u0000\is this nul terminated?"

19:24 clojurebot: #<RuntimeException java.lang.RuntimeException: Unsupported escape character: \i>

19:24 TEttinger: ,"\u0000hey!\u0000is this nul terminated?"

19:24 clojurebot: "

19:24 TEttinger: woah

19:28 Atlas_darkly: wut

19:36 TEttinger: ,(count "\u0000hey!\u0000is this nul terminated?")

19:36 clojurebot: 29

19:36 TEttinger: weird

19:36 TimMc: Maybe an IRC thing.

19:40 Atlas_darkly: yo

19:43 TimMc: &"\u0000"

19:43 lazybot: ⇒ "

19:43 TimMc: foobar

19:44 hmm, can't type a NUL in irssi

20:17 creese: Does the core lib have anything that format a string using values from a map?

21:05 gfredericks: creese: no but I wrote such a thing

21:06 creese: https://github.com/gfredericks/like-format-but-with-named-args

21:43 ToBeReplaced: creese: gfredericks: org.clojure/core.incubator gives clojure.core.strint

21:44 gfredericks: yep

21:45 Atlas_darkly: Madmao was better

22:06 StarBreaker: Atlas_darkly: :)

22:07 Atlas_darkly: How do you tag someone in a comment like that? (New to IRC

22:07 )

22:09 StarBreaker: Depends on the client you use, but generally it works when you type the beginning of the nick and hit tab

22:10 Atlas_darkly: thanks

22:11 StarBreaker: np

22:16 gniquil: clojure noob here, but which text editor should I use. I am most familiar with Sublime but it seems there's nothing good for Sublime3. And I also use Vim a lot. Any suggestions? Oh and Vundle or Pathogen?

22:21 amalloy: gniquil: use the one you're familiar with. i'm fairly sure there are people who use sublime text, although it is sorta last on my list of "clojure editors to recommend"

22:21 if you're also comfortable with vim i'd recommend that over ST

22:22 gniquil: I am mostly... been using it for 5 years prior, but haven't been my main editor for last 1

22:22 but then I found these pathogen and vundle debate

22:22 the quote complete thing really bugs me in Sublime text

22:23 and no repl integration (at least haven't found anything yet)

22:43 kristof: People don't use emacs anymore?

22:43 * kristof reconsiders his church membership

22:44 tbaldridge: sure we do. About 50% of Clojure devs use Emacs

22:44 The rest of us use vi, or Cursive, or something else

22:44 blkcat: i'm not even an emacs fan and i still use emacs when working with clojure

22:44 kristof: curious why amalloy didn't mention it then :(

22:44 gfredericks: he's overcompensating

22:44 kristof: oh good

22:45 amalloy: kristof: of course people use emacs. but i was being asked by a vim user

22:45 and recommending that he use emacs was wrong

22:45 kristof: amalloy: I didn't read that part of his question, I'm sorry

22:45 tbaldridge: That being said, I used to use emacs, but don't care for it anymore.

22:45 kristof: tbaldridge: Oh that's interesting. All the videos I've ever seen you in use emacs.

22:46 tbaldridge: Yep, I switched about a year ago, almost all my vids on pivotshare use Cursive

22:47 it's really hard to beat a custom tuned IDE. General use, customizable editors are great, but if all I do is program clojure, something that targets that directly is often much better.

22:47 At least that's been my experience with Cursive, PyCharm, and Visual Studio (for C#)

22:48 kristof: tbaldridge: I used Intellij a lot back when I was using java and liked it a fair bit, so I'm glad to see that Cursive builds on that

Logging service provided by n01se.net