2015-06-06
| 00:29 | amalloy | luxbock: (defmacro on-error-goto-next ...) |
| 00:42 | luxbock | (into {} x) is always eager right? |
| 00:42 | luxbock | i.e. I don't have to wrap the for in (into {} (for [...])) into a doall |
| 00:43 | justin_smith | luxbock: iirc into is as strict as the data structure, since it is just apply conj |
| 00:43 | luxbock | ah ok |
| 00:43 | justin_smith | $source inot |
| 00:43 | lazybot | Source not found. |
| 00:43 | justin_smith | $source into |
| 00:43 | lazybot | into is http://is.gd/caQYZB |
| 00:44 | justin_smith | well not *just* reduce conj, but essentially :) |
| 00:44 | luxbock | right, I should've known that |
| 03:00 | spacepluk | hi, is there any way to get a repl running on ios with lein-fruit? |
| 03:15 | Viesti | hum, which is more idiomatic, (clojure.string/join "" xs) or (apply str xs)? |
| 03:29 | alexyakushev | If you need it once per namespace, apply str is fine. Otherwise it's better to import join |
| 03:30 | alexyakushev | That's my rule of a thumb |
| 03:31 | alexyakushev | Besides, separator argument to join is optional |
| 03:31 | alexyakushev | ,(clojure.string/join [1 2 3]) |
| 03:31 | clojurebot | "123" |
| 03:45 | amalloy | use whichever one you want. nobody is very religious about this, except apparently alexyakushev |
| 03:48 | alexyakushev | Psst, wanna *join* this new cool cult? |
| 03:49 | alexyakushev | amalloy: Jokes aside, I expect apply anything version to be slower on large sequences |
| 03:49 | amalloy | no |
| 03:49 | amalloy | join is just implemented as a call to apply str. how else could it work? |
| 03:49 | alexyakushev | Sure about that? :D |
| 03:50 | amalloy | ~def clojure.string/join |
| 03:50 | alexyakushev | Ah, OK, I see now |
| 03:50 | alexyakushev | No-separator version is just apply str |
| 03:50 | alexyakushev | I accept my defeat |
| 03:51 | amalloy | and of course the body of str looks like the with-separator version of join |
| 03:54 | alexyakushev | Still, if join was implemented with explicit loop, it could be faster than apply, right? |
| 03:55 | amalloy | no |
| 03:55 | amalloy | apply str *is* implemented with the explicit loop you are talking about |
| 03:57 | alexyakushev | I'm kinda confused with this `spread` thing |
| 03:58 | amalloy | spread is just apply list |
| 03:58 | amalloy | but it's implemented before apply exists, in order to implement apply |
| 04:07 | alexyakushev | The world I've been living in crumbles, what you gonna do |
| 04:07 | alexyakushev | Thanks for the revelations |
| 04:08 | alexyakushev | 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 |
| 04:12 | amalloy | alexyakushev: generally if apply and reduce do the same thing for a particular function, apply will always be at least as fast |
| 04:13 | amalloy | because apply can just delegate to reduce, but the opposite is not true |
| 04:14 | amalloy | 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 |
| 04:18 | mmeix | so (apply + ...) would be preferable to (reduce + ...) in all cases? |
| 04:19 | mmeix | (for this one function '+', of course) |
| 04:19 | mmeix | ? |
| 04:21 | alexyakushev | Multiarity + is implemented via reduce |
| 04: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 |
| 04:24 | amalloy | my advice is to not actually worry about which one you use |
| 04:24 | mmeix | so if in doubt decide for readability/understandability |
| 04:25 | mmeix | ad hoc question - re naming: what would be preferable: :stemup :stemUp :stem-up? |
| 04:26 | mmeix | stylewise |
| 04:26 | mmeix | (with the other one being :stemdown ...) |
| 04:26 | amalloy | the - |
| 04:27 | mmeix | thanks |
| 04:27 | mmeix | (thought so) |
| 05: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? |
| 05:15 | scottj | kaffeeboehnchen: you require test.something not something. |
| 05:15 | scottj | kaffeeboehnchen: test.something/run-this if you just have that basic require |
| 05:16 | TEttinger | :as can be used to make the name shorter |
| 05:16 | TEttinger | ,(require '[clojure.string :as cs]) |
| 05:16 | clojurebot | nil |
| 05:16 | scottj | kaffeeboehnchen: and :refer [run-this] so you can just refer to run-this |
| 05:16 | TEttinger | ,(cs/replace "hey guys" #" " ", all you ladies and ") |
| 05:16 | kaffeeboehnchen | ah, yeah, sorry, I have [test.something :as something] already. |
| 05:16 | clojurebot | "hey, all you ladies and guys" |
| 05:17 | kaffeeboehnchen | (it says "no such var run-this" by the way) |
| 05:18 | kaffeeboehnchen | *something/run-this |
| 05:18 | kaffeeboehnchen | hm |
| 05:20 | kaffeeboehnchen | this is my code: https://paste.xinu.at/m-Vpp/ |
| 05:21 | scottj | kaffeeboehnchen: in run-test, are you sure you want ((create-db).. not (create-db)...? |
| 05:22 | scottj | (not re your problem) |
| 05:22 | kaffeeboehnchen | scottj: Well, that fixed my problem. I thougt I was importing it wrong :D |
| 05:22 | kaffeeboehnchen | Thanks! |
| 05:23 | scottj | kaffeeboehnchen: maybe there was a compile error you didn't see |
| 05: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 |
| 05:38 | mmeix | (ah, didn't try reduce ... never mind) |
| 05:39 | TEttinger | hmmm |
| 05:51 | TEttinger | mmeix: |
| 05:51 | TEttinger | ,(apply merge-with vector (map hash-map (map :pos c) (map :step c))) |
| 05:51 | clojurebot | {:s1 [1 5], :s2 2} |
| 05:52 | TEttinger | that was fun, is it accurate? |
| 05:52 | TEttinger | (I defined c in a privmsg to clojurebot) |
| 05:53 | mmeix | yes, this is quite similar with what I've found in the meantime: |
| 05:53 | mmeix | ,(let [c [{:step 1, :pos :s1} |
| 05:53 | mmeix | {:step 2, :pos :s2} |
| 05:53 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 05:53 | mmeix | {:step 5, :pos :s1}]] |
| 05:53 | mmeix | (->> (map #(hash-map (:pos %) (:step %)) c) |
| 05:53 | mmeix | (apply merge-with vector))) |
| 05:54 | mmeix | umpf |
| 05:54 | TEttinger | heh |
| 05:54 | mmeix | ,(->> (map #(hash-map (:pos %) (:step %)) c) (apply merge-with vector)) |
| 05:54 | clojurebot | {:s1 [1 5], :s2 2} |
| 05:55 | mmeix | ah! |
| 05:55 | TEttinger | nice! |
| 05:55 | mmeix | now if I wanted every val to be a vector? |
| 05:59 | mmeix | {:s1 [1 5], :s2 [2] } |
| 05:59 | TEttinger | ,(apply merge-with #(into [] %&) (map hash-map (map :pos c) (map :step c))) |
| 05:59 | clojurebot | {:s1 [1 5], :s2 2} |
| 05:59 | TEttinger | hm |
| 06:01 | mmeix | ah! |
| 06:01 | mmeix | ,(->> (map #(hash-map (:pos %) [(:step %)]) c) |
| 06:01 | mmeix | (apply merge-with into)) |
| 06:01 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 06:01 | mmeix | urx |
| 06:01 | mmeix | , (->> (map #(hash-map (:pos %) [(:step %)]) c) (apply merge-with into))) |
| 06: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 ... |
| 06: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))) |
| 06:02 | clojurebot | {:s1 [1 5], :s2 [2]} |
| 06:02 | mmeix | bingo |
| 06:03 | mmeix | just learned a lesson: make every element the same shape |
| 06:03 | mmeix | before into'ing |
| 06:04 | mmeix | (does clojurebot garbage collect defs?) |
| 06:05 | TEttinger | yes |
| 06:05 | mmeix | so c vanished after a short time - nice! |
| 06:05 | TEttinger | ,(def c [{:step 1, :pos :s1} {:step 2, :pos :s2} {:step 5, :pos :s1}]) |
| 06:05 | clojurebot | #'sandbox/c |
| 06:05 | TEttinger | ,(->> (map #(hash-map (:pos %) [(:step %)]) c) (apply merge-with into))) |
| 06:05 | clojurebot | {:s1 [1 5], :s2 [2]} |
| 06:05 | mmeix | great |
| 06:06 | mmeix | thanks for brain storming! |
| 06:09 | TEttinger | yeah, glad to help! |
| 06:10 | mmeix | the Clojure mindset is growing :) |
| 06: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 |
| 06:10 | mmeix | wow! |
| 06:10 | TEttinger | (hilariously, the hardest bug would never have happened in clojure, since I was missing a return statement) |
| 06:11 | mmeix | is Lua something to be interested in? |
| 06: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 :) |
| 06:11 | mmeix | brain twisting ... |
| 06:12 | TEttinger | I'm not sure. LuaJIT is absolutely amazing as far as dynamic language compilers go |
| 06:12 | TEttinger | I've been taking a functional programming lib for Lua and making it... more clojurey. |
| 06:12 | TEttinger | https://github.com/rtsisyk/luafun |
| 06:12 | TEttinger | I added reductions and made a correct partition |
| 06:13 | TEttinger | (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)]) ) |
| 06:14 | mmeix | quite a undertaking! (to much for a beginner's mind :-) |
| 06:14 | justin_smith | TEttinger: that's like an anemic group-by |
| 06:14 | TEttinger | all of this has been great fun |
| 06:14 | mmeix | I can imagine that |
| 06:16 | mmeix | could that become: (fn [f coll] ((juxt filter remove) f coll)) ? |
| 06:17 | mmeix | (I do have a love affair with juxt since yesterday) |
| 06:17 | mmeix | :D |
| 06:17 | TEttinger | yep! |
| 06:18 | justin_smith | mmeix: ##((juxt #(% true) #(% false)) (group-by even? (range 10))) |
| 06:18 | lazybot | ⇒ [[0 2 4 6 8] [1 3 5 7 9]] |
| 06:18 | justin_smith | it's better because it only walks once (but worse because not lazy) |
| 06:18 | oddcully | ,(map (just :pos :step) c) |
| 06: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... |
| 06:19 | oddcully | just that is... brain was typing and reading stuff from ju[sx]tin |
| 06:19 | TEttinger | oddcully with the long distance pass! |
| 06: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}) |
| 06:35 | mmeix | after trying, I see the elegance of (juxt :pos :step), but I'm not sure, what this buys me ... |
| 06:35 | mmeix | but I have to refill to maps and then merge-with ... |
| 06:37 | mmeix | right now it is a two-liner: |
| 06:37 | mmeix | (fn [c] (->> (map #(hash-map (:pos %) [(:step %)]) c) (apply merge-with into))) |
| 06:37 | mmeix | but destructuring - yes! |
| 06:37 | mmeix | trying more variations ... |
| 06:39 | oddcully | destructing won't help the golfing. i just find it easier to read |
| 06:40 | mmeix | (no aspiring for golfing, just a concise form) |
| 06:40 | mmeix | (and learning, of course) |
| 06:44 | oddcully | and there is select-keys |
| 06:45 | justin_smith | ,(select-keys (group-by even? (range 10)) [true false]) |
| 06:45 | clojurebot | {true [0 2 4 6 8], false [1 3 5 7 9]} |
| 06:54 | mmeix | two new versions: |
| 06:54 | mmeix | https://www.refheap.com/102152 |
| 06:54 | mmeix | pondering, which one I like more ... |
| 06: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. |
| 06:59 | mmeix | (scratch that, of course: https://www.refheap.com/102153) |
| 07:14 | justin_smith | ,(apply zipmap ((juxt (comp list :pos) (comp list vector :step)) {:step 1, :pos :s1})) |
| 07:14 | clojurebot | {:s1 [1]} |
| 07:15 | mmeix | ah ... |
| 07:15 | justin_smith | point-free, heh |
| 07:18 | mmeix | elegant! just trying ... has to work on a coll like [{:step 1, :pos :s1} {:step 2, :pos :s2}] |
| 07:18 | justin_smith | right, you would map it |
| 07:19 | justin_smith | ,(map (partial apply zipmap ((juxt (comp list :pos) (comp list vector :step))) [{:step 1, :pos :s1} {:step 2 :pos :s2}])) |
| 07: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... |
| 07:19 | justin_smith | err |
| 07:19 | justin_smith | ,(map (partial apply zipmap (partial (juxt (comp list :pos) (comp list vector :step))) [{:step 1, :pos :s1} {:step 2 :pos :s2}])) |
| 07:19 | clojurebot | #object[clojure.core$map$fn__4547 0x33a58260 "clojure.core$map$fn__4547@33a58260"] |
| 07:20 | justin_smith | err... |
| 07:20 | justin_smith | something like this, I probably should go back to sleep |
| 07:31 | mmeix | lots of options! |
| 07: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}]) |
| 07:34 | clojurebot | ({:s1 [1]} {:s2 [2]}) |
| 07:34 | justin_smith | point free starts to get kind of silly |
| 07:36 | justin_smith | ,(map (comp (partial apply zipmap) (juxt (comp list :pos) (comp list vector :step))) [{:step 1, :pos :s1} {:step 2 :pos :s2}]) |
| 07:36 | clojurebot | ({:s1 [1]} {:s2 [2]}) |
| 07:42 | TEttinger | nice try, justin_smith |
| 07:43 | justin_smith | ,(map (comp (partial apply hash-map) (juxt :pos (comp vector :step))) [{:step 1, :pos :s1} {:step 2 :pos :s2}]) |
| 07:43 | clojurebot | ({:s1 [1]} {:s2 [2]}) |
| 07:44 | TEttinger | ,(def c [{:step 1, :pos :s1} {:step 2, :pos :s2} {:step 5, :pos :s1}]) |
| 07:44 | clojurebot | #'sandbox/c |
| 07:46 | justin_smith | ,(apply merge-with into (map (comp (partial apply hahs-map) (juxt :pos (comp vector :step))) c)) |
| 07: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... |
| 07:46 | TEttinger | hah |
| 07:46 | justin_smith | ,(apply merge-with into (map (comp (partial apply hash-map) (juxt :pos (comp vector :step))) c)) |
| 07:46 | clojurebot | {:s1 [1 5], :s2 [2]} |
| 07:46 | TEttinger | hahsmap |
| 07:46 | TEttinger | there we go! |
| 07:46 | justin_smith | point-free is crazy |
| 07:46 | TEttinger | what is point-free? |
| 07:47 | TEttinger | no definitions? |
| 07:47 | justin_smith | TEttinger: no named bindings |
| 07:47 | TEttinger | ah |
| 07:47 | justin_smith | where % also counts as a name |
| 07:47 | TEttinger | is %& a named binding? |
| 07:47 | justin_smith | yes |
| 07:47 | justin_smith | it's a name, you can position it arbitrarily in a form |
| 07:47 | TEttinger | how would you do varargs in point-free |
| 07:47 | TEttinger | err |
| 07:47 | TEttinger | can you? |
| 07:48 | justin_smith | TEttinger: sure, apply |
| 07:48 | TEttinger | oh nvm |
| 07:48 | justin_smith | well, apply explits existing varargs |
| 07:48 | TEttinger | ,(defn [& args other] (apply str other args)) |
| 07: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... |
| 07:48 | TEttinger | ,(defn guh [& args other] (apply str other args)) |
| 07: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... |
| 07:49 | justin_smith | TEttinger: do you mean [other & args] ? |
| 07:49 | TEttinger | <justin_smith> it's a name, you can position it arbitrarily in a form |
| 07:49 | TEttinger | that was what I was testing |
| 07:49 | justin_smith | TEttinger: not the binding vector |
| 07:49 | justin_smith | the binding you create |
| 07:49 | TEttinger | it's still a form, the binding vector! |
| 07:50 | justin_smith | TEttinger: yes, in [& args] args is a binding, because you can use args anywhere in the following form |
| 07:50 | TEttinger | good ol' sleeping pills making me trollishly pedantic |
| 07:50 | justin_smith | I was not meaning to imply you can rearrange the binding vector itself, that's just silly |
| 07:50 | justin_smith | haha |
| 07:51 | mmeix | madstructuring, so to say :D |
| 07:51 | mmeix | (mmeix returns to listening & learning) |
| 07:52 | justin_smith | TEttinger: anyway, if you have a binding form of any sort, you definitely aren't point-free |
| 07:52 | TEttinger | ah! |
| 07:53 | justin_smith | let me see if I can recall all the ingredients needed for point-free in clojure... |
| 07:53 | TEttinger | ,(partial + (map inc (range 5))) |
| 07:53 | clojurebot | #object[clojure.core$partial$fn__4525 0xad60240 "clojure.core$partial$fn__4525@ad60240"] |
| 07:53 | justin_smith | juxt, comp, partial, apply |
| 07:53 | TEttinger | ((partial + (map inc (range 5))) (range 10 20)) |
| 07:53 | justin_smith | sadly we don't have flip |
| 07:53 | TEttinger | ,((partial + (map inc (range 5))) (range 10 20)) |
| 07: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... |
| 07:53 | justin_smith | I think you need apply there |
| 07:54 | TEttinger | how would you get the partial to take 1 of 2 seq arguments? |
| 07:54 | TEttinger | map can take any number of seqs |
| 07:54 | TEttinger | what if you want a partial that only has one of them supplied |
| 07:55 | justin_smith | ,((partial map + (map inc (range 5))) (range 10 20)) |
| 07:55 | clojurebot | (11 13 15 17 19) |
| 07:55 | TEttinger | oh herp |
| 07:55 | TEttinger | (inc justin_smith) ; a thousand times again |
| 07:55 | lazybot | ⇒ 260 |
| 07:56 | mmeix | is point-free-ness something to strive for, besides elegance? |
| 07:56 | justin_smith | ,((partial map + (map inc (range 5))) (range 10 20) (range 420 42)) |
| 07:56 | clojurebot | () |
| 07:56 | TEttinger | mmeix, oh ni |
| 07:56 | TEttinger | no |
| 07:56 | justin_smith | ,((partial map + (map inc (range 5))) (range 10 20) (range 42 420)) |
| 07:56 | clojurebot | (53 56 59 62 65) |
| 07:56 | TEttinger | it impairs readability IMO |
| 07:56 | justin_smith | mmeix: it's considered a style to strive for in haskell |
| 07:56 | TEttinger | programming is about assigning good names to complex things |
| 07:56 | justin_smith | but without currying it makes much less sense |
| 07:57 | justin_smith | and even with currying people find it baffling |
| 07:57 | mmeix | but it is good training :-) |
| 07:57 | mmeix | something I wanted to ask yesterday: do let-bindings bring a performance penalty with them? |
| 07:57 | justin_smith | it's a good thought exercise, I find |
| 07:58 | justin_smith | mmeix: not noticible ones, no |
| 07:58 | mmeix | or a memory |
| 07:58 | mmeix | penalty |
| 07:58 | justin_smith | clojure does locals clearing |
| 07:58 | justin_smith | so not usually an issue |
| 07:58 | mmeix | so they get garbage collected early |
| 07:58 | justin_smith | mmeix: if the compiler can know they can't escape scope, yes |
| 07:59 | mmeix | ah, sounds logical |
| 07:59 | justin_smith | but the compiler is intentionally a bit daft |
| 07:59 | justin_smith | we don't try to make the compiler super clever, unlike most mainstream languages |
| 08:00 | mmeix | how does this look in clojurescript? would I strive for memory/speed in this way? (thinking tablets etc.) |
| 08:03 | mmeix | I always thougt, "partial" is currying ... |
| 08:11 | stain | more (partial)? |
| 08:12 | mmeix | ? |
| 08:12 | stain | ah, it's a different discussion. it was discussed earlier in the week, lambda vs partial |
| 08:13 | mmeix | no, the context here was point-free functions, and their usefulness/... |
| 08:14 | mmeix | if I got that right :) |
| 08:18 | stain | ah |
| 08:18 | mmeix | Justin wrote a solution for a function I tried |
| 08:18 | stain | lazy sequences are kind of also in the same field.. but that's more with performance than with doing a pipeline style |
| 08:19 | stain | in my never-available time I try to write a workflow language for composing clojure functions, where you just state the connections |
| 08:19 | TEttinger | nice, stain |
| 08:20 | mmeix | that sounds interesting |
| 08:20 | stain | it's not very different from working with futures |
| 08:20 | stain | except that I want it to be push rather than pull |
| 08:24 | mmeix | would this resemble a glorified threading macro? |
| 08:25 | mmeix | (sorry, glorified is not a proper word maybe, bear with non native speakers ...) |
| 08: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)) |
| 08:25 | stain | something like that.. just independent connections from outputs to parameters |
| 08:25 | stain | obviously you can link the same output to multiple destinations |
| 08:26 | mmeix | reminds me of old school Moog Synthesizers :D |
| 08:26 | stain | but not so easily the other way around |
| 08:26 | mmeix | in studio language the use fan-in and fan-out for that |
| 08: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 |
| 08:27 | mmeix | multiple inputs would need a standard "summing" function, I guess |
| 08:27 | stain | and if you give a list to somethign that expects a value, autoamtic (map) |
| 08:27 | mmeix | ah! |
| 08:27 | stain | but that's a bit trickier in Clojure where generally parameters don't have a defined list depth |
| 08:27 | stain | but perhaps my defstep could allow that |
| 08:28 | stain | it would mean a more complex workflow compilation which can't be done before the whole workflow is defined |
| 08:28 | mmeix | exciting! |
| 08:29 | mmeix | needs a HyperREPL |
| 08:29 | stain | really I am just looking at a way to throw out our existing Taverna workflow engine and translate to Clojure code |
| 08:29 | stain | as then it could basically be compiled down to run directly on the JVM.. currently it runs in kind of "interpreted" mode |
| 08:30 | stain | 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 |
| 08:30 | mmeix | I could use something like that for my music project |
| 08:30 | stain | mmeix: so then you would have basically an endless stream of signals, right? |
| 08:31 | mmeix | right |
| 08:31 | stain | it sounds like you would need a clock-based workflow |
| 08:31 | mmeix | not necessarily |
| 08:31 | mmeix | it could produce several related versions of something |
| 08:32 | mmeix | reminds me a bit of http://en.wikipedia.org/wiki/Max_(software) |
| 08: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? |
| 08:33 | stain | depends if you want digital or analog synth in a way :) |
| 08:33 | mmeix | yes |
| 08:33 | stain | in analog you would appreciate those kind of aritfacts |
| 08:33 | mmeix | some signals could be Audio related |
| 08:33 | mmeix | some would carry semantic data |
| 08:34 | mmeix | or notation |
| 08:34 | mmeix | example: https://cycling74.com/2013/01/24/bach-beta-0-7-release/ |
| 08:36 | mmeix | Web Audio has a similar concept |
| 08:36 | stain | cool stuff |
| 08:36 | mmeix | yes ... the MAX people are around for a long time now |
| 08:37 | mmeix | this is coming from developments in Paris IRCAM initally |
| 08:37 | mmeix | and Clojure lends itself to those concepts |
| 08:37 | mmeix | this is, why I'm learning it now |
| 08:38 | mmeix | there is a very long tradition of using LISPs in music generation |
| 08:38 | mmeix | decades, in fact |
| 08:38 | mmeix | it makes sense: musical data is a stream of values, and lists |
| 08:39 | mmeix | :D |
| 08:39 | stain | someone used Taverna workflows to compose music as well: http://www.taverna.org.uk/introduction/taverna-in-use/arts/composition-of-music/ |
| 08:39 | mmeix | ah, thanks for the link! |
| 08: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 |
| 08:40 | stain | but that's a bit of a long shot |
| 08:40 | mmeix | let me know of the project! or can I follow you somewhere? |
| 08:40 | stain | as I don't have time to replicate the more powerful workflow engine features (e.g. automatic retries on failures) |
| 08:40 | stain | uhm.. it's.. mainly in my head! |
| 08:40 | stain | I'm on the twitter @soilandreyes |
| 08:40 | mmeix | np |
| 08:40 | stain | you've inspired me to have a go :) |
| 08:41 | mmeix | we live in excitig times, I find |
| 08:41 | stain | too many ideas, too little time |
| 08:41 | mmeix | yes, same here |
| 08:41 | mmeix | just now coming to grips with Clojure while programming a web based music notation lib |
| 08:42 | mmeix | with thinking about implementing musical semantics on a deeper level |
| 08:43 | mmeix | so lot of ideas too :-) |
| 08:43 | sobel | seems like this discussion might be incomplete without mentioning Overtone |
| 08:43 | mmeix | Yes, O know Overtone |
| 08:43 | mmeix | I |
| 08:43 | mmeix | the synthesis side of it is great, the underlying musical semantics a bit to naive, I find |
| 08:43 | sobel | agreed |
| 08:44 | sobel | i looked straight at building instruments and puked at the amount of work left to the music developer |
| 08:44 | mmeix | musical semantics go through many levels |
| 08:44 | mmeix | the MIDI-centered view is not expressive enough |
| 08: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 |
| 08:45 | mmeix | Clojure can do better, I think |
| 08:45 | mmeix | yes |
| 08:45 | kaffeeboehnchen | Anyone has an idea how I can create a foreign key with java.jdbc? |
| 08:45 | sobel | agreed again on MIDI-centric being a poor model |
| 08:45 | mmeix | MIDI was invented for making another synth play |
| 08:45 | mmeix | so it has really very little meaning |
| 08:45 | sobel | right. in a pretty generic sense. |
| 08:46 | sobel | worse, it assumes stateful controllers and a bunch of other crud |
| 08:46 | mmeix | musical structure is a very deep thing |
| 08:46 | sobel | :) |
| 08:46 | sobel | talk to me |
| 08:46 | mmeix | as I can confirm |
| 08:47 | mmeix | (I'm teaching music theory in Vienna University for music) |
| 08:47 | sobel | excellent |
| 08:47 | mmeix | yeah, and very happy to have found Clojure as a medium to work in |
| 08:47 | mmeix | now leraning frantically |
| 08:47 | mmeix | as the people here can attest ;-) |
| 08:48 | mmeix | lots of beginner's questions from my side |
| 08: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. |
| 08:48 | mmeix | great! |
| 08: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. |
| 08:49 | mmeix | why not? |
| 08:49 | sobel | downside is i still suck at it and the tooling isn't polished like Ableton so, lotsa pitfalls |
| 08:50 | mmeix | yes ... |
| 08:50 | sobel | why am i not a GUI person anymore? probably broken by years of software eng |
| 08:50 | mmeix | LOL |
| 08:50 | mmeix | but thinking in functions is very similar to thinking music |
| 08: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 |
| 08:51 | mmeix | ja, they are ugly often |
| 08:51 | mmeix | we will change that :-) |
| 08:51 | mmeix | when I have my music notetion engine running, I'll dive deep into semantics |
| 08:51 | mmeix | hopefully this summer |
| 08:52 | mmeix | *notation |
| 08: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. |
| 08:52 | mmeix | you are a professional programmer? |
| 08:52 | sobel | yes |
| 08:52 | mmeix | oh, great |
| 08:53 | mmeix | I envy the pros a bit right now |
| 08:53 | mmeix | but everything can be learned |
| 08: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 |
| 08:54 | sobel | 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? |
| 08:55 | sobel | 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. :) |
| 08:55 | mmeix | computer technology seems to evolve very fast - but on the other side the return of LISPs from decades ago gives some hope |
| 08:55 | mmeix | for me |
| 08:56 | mmeix | so it's learning and learning |
| 08:56 | mmeix | I like this, OTOH |
| 08: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. |
| 08:57 | mmeix | back to the fathers! |
| 08:57 | mmeix | (same as back to JSBach :-) |
| 08:58 | mmeix | and Rich is a musician too, I learned ... |
| 08: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. |
| 08:58 | sobel | when i was a band student, most the programmers i knew were marching on the field with me every morning |
| 08:59 | mmeix | :-) |
| 08:59 | sobel | the rest dropped out of band in 9th grade. music/CS seem to be a really common combo, probably for the synergy. |
| 08:59 | sobel | or maybe it's due to the whole deal with musicians growing denser dendrite networks |
| 09:00 | mmeix | I heard a talk lately, which showed that the whole brain is exercised in musical activity |
| 09:00 | sobel | i think what i'd ideally like, is to be able to cram patterns into Ableton from a clojure repl |
| 09:00 | mmeix | I guess, we wouldnt need Ableton for that, but it should be possible ... |
| 09: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 |
| 09:01 | sobel | mmeix: i'd like to express patterns with dynamics in closed form at the REPL |
| 09:02 | mmeix | one could try OSC as a intermedita medium, I guess |
| 09:02 | sobel | instead of clicking them out or playing them in, then changing over to the controller view to draw the dynamic, etc |
| 09:02 | mmeix | I'm not sure, if Ableton supports OSC |
| 09:02 | mmeix | OSC is much richer than MIDI |
| 09:02 | sobel | there's a MIDIOsc server |
| 09:02 | mmeix | will think about that |
| 09:02 | mmeix | ah, ok |
| 09:02 | mmeix | OSC is simple text |
| 09:03 | sobel | dunno if it would meet the need but i used it to integrate a silly ipad app to ableton once |
| 09:03 | mmeix | so should totally be doable with Clojure as generator |
| 09:03 | mmeix | I used LEMUR for that |
| 09:03 | mmeix | great stuff |
| 09:03 | mmeix | more ideas for the summer :D |
| 09:04 | sobel | does LEMUR come with an app that makes midi from the LEMUR messages? |
| 09:04 | mmeix | ja |
| 09:04 | mmeix | there's a the usual desktop server app |
| 09:04 | mmeix | and LEMUR in itself has a rich scripting language |
| 09:05 | mmeix | https://liine.net/en/products/lemur/ |
| 09: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. |
| 09:05 | mmeix | should be easily doable in MAX |
| 09:06 | mmeix | there is a throttling module |
| 09: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 |
| 09:06 | mmeix | I forgot |
| 09:06 | sobel | oh cool |
| 09:06 | sobel | i usually don't end up on the max side (bad at GUIs!) |
| 09:08 | mmeix | https://docs.cycling74.com/max5/refpages/max-ref/speedlim.html |
| 09:09 | mmeix | I guess this could do what you want |
| 09:09 | mmeix | GUI-wise: three or four nodes to click together |
| 09:10 | mmeix | shouldn't be that bad |
| 09:10 | sobel | hmm. i don't want a rate limiter, i want to throw away the ones that are too fast. |
| 09: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." |
| 09:10 | sobel | so necessarily a slight delay |
| 09:11 | mmeix | if it's less than 20 ms or so, one woldn't perceive it, I guess |
| 09:11 | mmeix | and MIDI isn't that fast anyway :-) |
| 09:11 | sobel | not real MIDI |
| 09:12 | mmeix | there is an example on the bottom of the page, where they limit pitchbends |
| 09:13 | sobel | IIRC oh dear, the original spec was 3.125Kbps. i got on board when it was routinely run over 100k, ISTR. |
| 09: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 :-) |
| 09:15 | sobel | i bother justin_smith occasionally as well :) i'm around on and off throughout the year. be well! |
| 09:15 | mmeix | you too! |
| 10:14 | mmeix | what is common wisdom re default values for defrecord? |
| 10:14 | mmeix | I'm reading here: http://cemerick.com/2010/08/02/defrecord-slot-defaults/ |
| 10:14 | mmeix | he does a macro for this |
| 10:15 | mmeix | 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 | crocket | In java, I did. |
| 10:16 | crocket | 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 | mmeix | thanks! this makes sense ... |
| 10:41 | mmeix | so this would be a simple form of a constructor: |
| 10:41 | mmeix | (defn pitch [step & accidental] (map->Pitch {:step step :accidental :none})) |
| 10:41 | mmeix | 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 | mmeix | pitch would be part of a chord [pitch1 pitch2 pitch3] |
| 11:09 | mmeix | chord would be part of a graphical unit |
| 11:09 | mmeix | [chord stem flag dots] |
| 11:10 | mmeix | this unit has to do a lot of calculations to place symbols where they belong |
| 11:10 | mmeix | for example a function which cares for accidental placement |
| 11:10 | mmeix | and so on |
| 11:11 | mmeix | Would it be better to omit :accidental :none ? |
| 11:13 | mmeix | 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 | mmeix | this is the use case |
| 11:15 | mmeix | but if I do (defrecord Pitch [step accidental]) I'm obliged to supply a value for both, right? |
| 11:16 | mmeix | ,(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 | mmeix | ,(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 | mmeix | ,(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 | mmeix | 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 | mr_rm | sorry for kind of off topic but nobody talking in #vsclojure |
| 11:29 | mr_rm | e.g. reformatting changes (-> obj .Foo) to (-> obj . Foo) and this frequently causes errors |
| 11:43 | mr_rm | 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 | hadronzoo | 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 | Jickelsen | (#(let [c (chan)] (>! c "bar") c)) |
| 12:51 | Jickelsen | )] |
| 12:51 | Jickelsen | foo)) |
| 12:51 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 12:53 | Jickelsen | Returns #<[Object Object]> |
| 12:53 | Jickelsen | nil |
| 12:53 | Jickelsen | for me |
| 12:54 | gfredericks | is it a channel? |
| 12:54 | gfredericks | 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 | justin_smith | 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 | gfredericks | and we are all different slices of a very finely sliced pumpkin pie |
| 13:02 | Jickelsen | I tried switching out foo for a global atom |
| 13:02 | Jickelsen | (go (reset! foo (<! |
| 13:02 | Jickelsen | (#(let [c (chan)] (>! c "bar") c)) |
| 13:02 | Jickelsen | )) but the value of foo has not been changed |
| 13:02 | Jickelsen | 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 | justin_smith | gfredericks: ahh, OK |
| 13:04 | justin_smith | 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 | justin_smith | ,(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 | Jickelsen | (go (reset! foo (<! |
| 13:17 | Jickelsen | (let [c (chan)] (>! c "bar") c)))) |
| 13:17 | Jickelsen | 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 | justin_smith | or maybe false |
| 13:19 | justin_smith | ,((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 | justin_smith | Jickelsen: I can reproduce, doing it inside one go block fails |
| 13:29 | justin_smith | 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 | justin_smith | 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 | justin_smith | 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 | mmeix | ,(defrecord Simpson [name hair]) |
| 13:47 | clojurebot | sandbox.Simpson |
| 13:47 | mmeix | ,(defn new-simpson [name & [hair]] |
| 13:47 | mmeix | (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 | mmeix | "[name & [hair]]" |
| 13:49 | mmeix | 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 | mmeix | 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 | mmeix | but that feels a bit convoluted too |
| 13:54 | mmeix | in a simple case of 1-3 args a variadic func is easy enough |
| 13:54 | mmeix | thanks again |
| 14:02 | mmeix | follow-up: |
| 14:02 | mmeix | ,(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 | justin_smith | 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 | mmeix | or "(defn pitch ([step] (pitch step :none))..." ? |
| 14:05 | justin_smith | mmeix: ahh |
| 14:06 | justin_smith | yeah, nil is idiomatic for "none" I think |
| 14:06 | mmeix | ok |
| 14:06 | mmeix | 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 | justin_smith | 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 | mmeix | (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 | justin_smith | 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 | justin_smith | 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 | justin_smith | dope has a complex dependency tree |
| 14:12 | justin_smith | coin flips are isolated :) |
| 14:13 | gfredericks | this is the OOP version of "simple" |
| 14:13 | gfredericks | all I have to do is call it.isDope() how could anything be simpler |
| 14:14 | gfredericks | 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 | gfredericks | 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 | gfredericks | which lib? |
| 14:20 | gfredericks | carbiou-core? |
| 14:20 | justin_smith | caribou-core is the db and modeling layer |
| 14:20 | justin_smith | caribou-admin is the web UI for CRUD |
| 14:20 | justin_smith | 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 | justin_smith | *various |
| 14:23 | justin_smith | 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 | justin_smith | the implementation uses jdbc for everything |
| 14:24 | justin_smith | 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 | justin_smith | 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 | gfredericks | with java.jdbc |
| 14:29 | gfredericks | 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 | gfredericks | types and keys |
| 14:32 | gfredericks | maybe prismatic/schema would be sufficient for that |
| 14:32 | gfredericks | or at least could be an implementation |
| 14:33 | gfredericks | 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 | dhardison | 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 | justin_smith | dhardison: and definitely use the chrome inspector / console if you are not yet |
| 14:36 | justin_smith | 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 | justin_smith | though you do have to figure out the "munging" to get the js version of the thing you want |
| 14:43 | justin_smith | but that's where the figwheel repl also helps - it's a cljs repl |
| 14:43 | justin_smith | 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 | noncom | i mean, it is no longer done through STM ? |
| 16:39 | justin_smith | noncom: how would it modify the {} |
| 16:39 | justin_smith | 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 | noncom | 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 | justin_smith | ,(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 | noncom | ,(.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 | noncom | cool! :) |
| 16:42 | noncom | 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 | justin_smith | ,(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 | justin_smith | ,(.get (doto (java.util.HashMap. {:a 0}) (.put :b 1)) :b) |
| 16:45 | clojurebot | 1 |
| 16:47 | noncom | i see! |
| 16:47 | noncom | 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 | clojurebot | #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 | dhardison | 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 | justin_smith | ,(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 | clojurebot | 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 | dhardison | 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 | thedoodPL | 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 | dhardison | i'll have to do a reset! |
| 17:51 | oddcully | danlarkin: swap! |
| 17:51 | oddcully | erm |
| 17:51 | oddcully | dhardison: ^^ |
| 17:53 | dhardison | oddcully: i'm passing in the atom into a function -- will that still work |
| 17:53 | dhardison | 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 | TimMc | 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 | gfredericks | 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 | Atlas_darkly | ) |
| 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 | amalloy | 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 | gniquil | but then I found these pathogen and vundle debate |
| 22:22 | gniquil | the quote complete thing really bugs me in Sublime text |
| 22:23 | gniquil | and no repl integration (at least haven't found anything yet) |
| 22:43 | kristof | People don't use emacs anymore? |
| 22:44 | tbaldridge | sure we do. About 50% of Clojure devs use Emacs |
| 22:44 | tbaldridge | 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 | amalloy | 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 | tbaldridge | 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 | tbaldridge | 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 |