#clojure log - Sep 09 2015

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

0:14 ska-fan: Hmm, how do I produce either [a b c] or [a c] depending on some condition without mentioning a or c twice (i.e. not (if cond? ([a b c]) ([a c])))? Or is that an achievement that is worth nothing in functional world?

0:15 justin_smith: ska-fan: ##(if false [a b c] [a c]) -- your version has way too many parens

0:15 Bronsa: ska-fan: you'll have to go with the repetition

0:16 ska-fan: Bronsa: I thought so. Thanks :)

0:18 justin_smith: Thanks! Learning two languages at a time (the other is racket) I get confused :)

0:25 Any other way to make this more concise? https://gist.github.com/mbertheau/6f7debba1a8943930c13

0:26 justin_smith: ska-fan: you can define final-style within the outer let block

0:26 you don't need nested let for that

0:26 bufh: hi

0:27 justin_smith: (that is, base style and final style can be moved into the top level let, before normal-bar)

0:28 bufh: I am just beginning to learn clojure - can someone point out ways of making this code more efficient? (https://gist.github.com/singhgurjeet243/208a345c17e8a35fc0be)

0:30 justin_smith: bufh: you could use a transducer instead of reduce and map - unlike a transducer, the map produces a lazy seq you don't need

0:31 bufh: justin_smith: are there examples of transducers you can point me to?

0:32 justin_smith: bufh: this is the best intro http://clojure.org/transducers

0:32 bufh: justin_smith: thanks!

0:32 TEttinger: it's not quite a beginner thing, transducers, but I think that's mostly because they are, relatively speaking, new. there's nothing terribly complex about them as a concept I think

0:32 justin_smith: so instead of reduce + (map f c) you can use transduce + (map f) + c

0:33 TEttinger: well, he was asking about performance, which isn't a beginner thing either is it?

0:33 TEttinger: I suppose. transducers do seem like a good route here

0:33 bufh: I am not a CS beginner, just a clojure beginner :)

0:34 justin_smith: bufh: transducers are pretty unique, and are lower level and more specific than people seem to expect

0:34 bufh: justin_smith: seems like it, I haven't seen them in scala or haskell

0:34 justin_smith: they replace using a sequence as the universal abstraction with a more general "source of data" and "consumer of data" abstraction

0:35 for things like channels, or multi step transforms, where fully implementing sequences is just overhead

0:35 bufh: haskell doesn't need it because they have a clever compiler, clojure is intentionally unclever

0:35 bufh: is there a 'zen of clojure' a-la python?

0:35 justin_smith: there's definitely a unique clojure approach

0:36 stuff on clojure.org, plus conj.io, plus examples and suggestions here on IRC will help you figure it out pretty quick I think

0:36 http://conj.io/

0:37 bufh: sweet

0:38 TEttinger: justin_smith: interestingly, when I looked at bufh's the code the first thing I thought was "this could be faster if it used mutable state in sample". I don't know if that's accurate though

0:38 justin_smith: I don't think mutation would give any advantage in there that a transducer wouldn't

0:39 bufh: also, just for a lark you could try explicitly using first and second in the definition of test-point - destructuring has a bit of overhead you might want to avoid in a bottleneck

0:40 TEttinger: well there's some obvious speedup in using unchecked math and making sure the numbers are type-hinted

0:40 or merging test-point and gen-point into one fn since they're always together

0:40 justin_smith: oh yeah, some type hints in a few places would likely help, yeah

0:41 bufh: hm, I don't know how to use type hints yet

0:41 TEttinger: you'll want that reflection warning for math thing that got added in 1.7

0:41 justin_smith: bufh: http://clojure.org/java_interop#Java Interop-Type Hints

0:41 oh man, that's not a real link

0:41 TEttinger: it would show you where numbers are being boxed (objects, reference types, heavier weight) or are being calculated with primitives

0:42 justin_smith: http://clojure.org/java_interop#Java%20Interop-Type%20Hints

0:42 TEttinger: this one http://clojuredocs.org/clojure.core/*unchecked-math*

0:43 math-heavy code can be unusually slow in clojure if you aren't aware of how boxing works and when you want to avoid it

0:44 boxing is needed to put a primitive int into a collection of any kind, where it becomes an Integer

0:44 puredanger: A general rule of thumb is that boxed math is about 100x slower than primitive math

0:44 bufh: got it, I understand boxing/unboxing on the JVM, but didn't know how to use it in clojure

0:44 justin_smith: 100 is a big number

0:45 TEttinger: ,36r100 ;; is bigger

0:45 clojurebot: 1296

0:45 bufh: so, how can I ensure, that e.g. gen-point generates an array of double in the JVM as opposed to an array of Double

0:45 ?

0:45 TEttinger: that would be two parts.

0:45 justin_smith: bufh: well, you would need to use an array first

0:45 you can't put primitives in vectors

0:46 (well, not in normal ones)

0:46 TEttinger: they can be put in, they will just change to boxed versions, like int to Integer

0:46 justin_smith: TEttinger: potato, potato

0:47 TEttinger: you're right about the array thing, and arrays are I think about as fast in clojure as they are in java :)

0:49 justin_smith: bufh: or, instead of an array or vector, you can use vector-of http://conj.io/store/v1/org.clojure/clojure/1.7.0/clj/clojure.core/vector-of/

0:49 in fact I think vector-of is probably the nicest option here

0:49 (other than unrolling the code so you don't need a collection at all)

0:50 puredanger: It only helps on memory

0:50 Primitive vecs still box in and out

0:50 justin_smith: puredanger: vector-of doesn't help with the boxing issue?

0:50 TEttinger: http://clojuredocs.org/quickref under java interop

0:50 justin_smith: oh

0:50 never mind then!

0:50 amalloy: ska-fan: another option is `[~a ~@(when cond? [b]) ~c]

0:50 TEttinger: ah!

0:51 ska-fan: amalloy: Hmm! Is that considered hacky?

0:51 amalloy: but that is some fancypants unquoting stuff that may just be distracting

0:51 *shrug* some people don't seem to like it. i am perfectly happy with it myself, and use it when it's convenient

0:51 justin_smith: ska-fan: it will make people think "hey, this guy is clever, like amalloy"

0:51 TEttinger: amalloy has some rather fancy pants

0:52 justin_smith: oh, not much, just on IRC, discussing some guy's pants

0:53 TEttinger: it's interesting; ~@ is rather often a potential part of a solution but not often used outside of things that are already loaded with macro goodness

0:53 ska-fan: I have this now: https://gist.github.com/mbertheau/6f7debba1a8943930c13 I guess I could go (let [be (if cond [b] [])] (concat [a] be [c])) but that doesn't strike me as particularly beautiful either.

0:54 TEttinger: ,(concat [:a] (if true :b) [:c])

0:54 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Keyword>

0:54 TEttinger: ,(concat [:a] (if true [:b]) [:c])

0:54 clojurebot: (:a :b :c)

0:54 TEttinger: ,(concat [:a] (if false [:b]) [:c])

0:54 clojurebot: (:a :c)

0:54 justin_smith: TEttinger: yeah, that's what the ~@ trick expands to, right?

0:54 TEttinger: not sure

0:54 ska-fan: ,[:a (if false :b) :c]

0:54 clojurebot: [:a nil :c]

0:55 TEttinger: the trick I was pointing out was that if returns nil if there's no else

0:55 amalloy: justin_smith: more or less

0:55 ska-fan: Ah, concat skips nil.

0:55 amalloy: ska-fan: not exactly

0:55 justin_smith: ,`(:a ~(if false [:b]) :c)

0:55 clojurebot: (:a nil :c)

0:55 amalloy: concat treats things as sequences, and nil is an empty sequences

0:55 justin_smith: err

0:55 ,`(:a ~@(if false [:b]) :c)

0:55 clojurebot: (:a :c)

0:55 justin_smith: ,'`(:a ~@(if false [:b]) :c)

0:55 clojurebot: (clojure.core/seq (clojure.core/concat (clojure.core/list :a) (if false [:b]) (clojure.core/list :c)))

0:55 justin_smith: oh yeah, that's about the same :)

0:56 TEttinger: interesting

1:00 bufh, heh, we got side-tracked for a moment with another good yak to shave. but I noticed that you might not actually need the array

1:00 since all your code is doing is conditionally incrementing a value

1:00 bufh: ok, how?

1:00 justin_smith: TEttinger: yeah, that's what I was getting at with unrolling

1:00 bufh: by combining those two separate functions (or splitting more finely)

1:00 such that you don't need the tuple

1:01 because your boxing will be caused by the part where you put the x and y in a collection

1:01 ska-fan: Hmm, filterv but no removev

1:02 bufh: ok, let me try it

1:12 hmm, so no appreciable speedup

1:12 https://gist.github.com/singhgurjeet243/208a345c17e8a35fc0be

1:13 justin_smith: bufh: oh wait I just realized why you call double on line 25

1:14 bufh: if you are doing rational math, the unboxing isn't possible - rational math is always slow, and there is no such thing as an unboxed rational

1:14 bufh: ok, but the rational math only enters in that line - after the heavy lifting is already done

1:14 justin_smith: oh... maybe the rational is only being produced in that one place though

1:14 haha, yeah

1:15 anyway, style wise I prefer (* 4.0 e) to (double (* 4 e))

1:15 bufh: infact the new sampler is slower

1:15 fair point

1:15 on style

1:15 justin_smith: oh, interesting...

1:16 bufh: but not by much

1:16 my suspicion is on the range there

1:16 justin_smith: I wonder if there's a place where hinting would help there...

1:17 amalloy: bufh: if you use (time) for profiling you will get very unreliable results

1:17 it's just for getting a rough idea of how long stuff is taking

1:17 you can get reasonable results from criterium instead, if you need to time things

1:17 bufh: ok, but if one approach was 10x faster, that'd probably show up, right?

1:18 amalloy: wellll, maybe. the jvm can do some strange things. often the second one you run is faster, because of JITing, or maybe the first one is faster because of GC...

1:18 10x is a lot, and i would expect that to usually correlate with actually being faster

1:18 but no guarantees, especially if it's like 5us vs 50us

1:18 ska-fan: Ha! (-> [:a] (into (if cond? [:b])) (into [:c])) What do you think?

1:18 justin_smith: ,(transduce + (map inc) [1 2 3 4])

1:18 bufh: ➜ pi lein run

1:18 "Elapsed time: 1510.67 msecs"

1:18 "Elapsed time: 1309.328 msecs"

1:19 clojurebot: #error {\n :cause "Wrong number of args (0) passed to: core/map/fn--4537"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (0) passed to: core/map/fn--4537"\n :at [clojure.lang.AFn throwArity "AFn.java" 429]}]\n :trace\n [[clojure.lang.AFn throwArity "AFn.java" 429]\n [clojure.lang.AFn invoke "AFn.java" 28]\n [clojure.core$transduce invokeStatic "core.clj" 6573]\...

1:19 amalloy: bufh: right, so that's easily within experimental error

1:19 justin_smith: ,(transduce + (map inc) 0 [1 2 3 4])

1:19 clojurebot: #error {\n :cause "Cannot cast clojure.core$map$fn__4537 to java.lang.Number"\n :via\n [{:type java.lang.ClassCastException\n :message "Cannot cast clojure.core$map$fn__4537 to java.lang.Number"\n :at [java.lang.Class cast "Class.java" 3176]}]\n :trace\n [[java.lang.Class cast "Class.java" 3176]\n [clojure.core$cast invokeStatic "core.clj" 338]\n [clojure.core$_PLUS_ invokeStatic "core.clj" ...

1:19 amalloy: criterium exists to give you a little more confidence in these estimates

1:20 ,(doc transduce)

1:20 clojurebot: "([xform f coll] [xform f init coll]); reduce with a transformation of f (xf). If init is not supplied, (f) will be called to produce it. f should be a reducing step function that accepts both 1 and 2 arguments, if it accepts only 2 you can add the arity-1 with 'completing'. Returns the result of applying (the transformed) xf to init and the first item in coll, then applying xf to that result and ...

1:20 amalloy: ,(transduce (map inc) + 0 [1 2 3 4]) ; ??

1:20 clojurebot: 14

1:20 justin_smith: ahh, I had the first two flipped!

1:21 bufh: that's for you ^ amalloy's example shows how to adapt what you have to a transducer (won't be a huge speedup, but should be a speedup)

1:22 bufh: sorry, I need a bit more help : how do I convert sample2 to use transducers?

1:22 justin_smith: bufh: where the above has inc, put your own fn

1:23 and where it has a vector, replace your range call

1:23 otherwise it is exactly like amalloy 's example

1:23 bufh: transduce replaces reduce

1:25 bufh: i am getting a compilation error: Unable to resolve symbol: transduce in this context

1:25 justin_smith: bufh: clojure version?

1:25 TEttinger: are you using clojure 1.7 or newer?

1:25 ,*clojure-version*

1:25 clojurebot: {:major 1, :minor 8, :incremental 0, :qualifier "alpha3"}

1:26 TEttinger: you can check with that in the REPL

1:26 bufh: its 1.6

1:26 ok, have to figure out how to upgrade

1:26 justin_smith: bufh: are you using leiningen?

1:26 bufh: yea

1:26 justin_smith: just change the version number in project.clj, clojure is just a library

1:27 bufh: also, with clojure 1.7 you can use *warn-on-boxed* for numeric ops

1:29 puredanger: (set! *unchecked-math* :warn-on-boxed)

1:29 justin_smith: :global-vars {*warn-on-reflection* true *unchecked-math* :warn-on-boxed}

1:30 ^ that for project.clj

1:31 bufh: wow boxing warnings across the board

1:31 luxbock: when you use (set! *unchecked-math* :warn-on-boxed) in a namsepace, does it apply only to that ns?

1:31 justin_smith: it is not namespace specific

1:32 it changes a var in clojure.core

1:32 luxbock: I would imagine having *unchecked-math* :warn-on-boxed turned globally on would be pretty annoying

1:32 guess you'd only use it when tweaking some specific thing

1:32 justin_smith: luxbock: it's the only option - though you can turn it off while compiling libs and then turn it on while loading your own code I guess

1:33 luxbock: the true root of the annoyingness is the libs that force numeric boxing, if they fix their shit you won't get annoying messages :)

1:33 luxbock: hmm I see

1:33 justin_smith: luxbock: I'm being glib about that

1:34 luxbock: I wouldn't actually know how to fix the boxed warnings in bufh's code, for example in `gen-point`

1:34 you'd just give type-hints for the return value?

1:34 justin_smith: luxbock: by using hints in the specific places where the compiler doesn't know the value can remain unboxed

1:34 bufh: ok I changed both samplers to xducers, both are 50% faster

1:34 justin_smith: nice!

1:35 ska-fan: What's short for (if (nil? a) 300 a) ?

1:35 justin_smith: the boxing warnings should help too, once you sort them out

1:35 (if-not a 300 a)

1:35 (or a 300)

1:35 that last one is my final answer

1:36 bufh: ok lots of boxing and unboxing going on - how do I eliminate it say in test-point ?

1:36 ska-fan: justin_smith: Thanks!

1:38 justin_smith: bufh: [[^double x ^double y]]

1:38 (in the args vector)

1:38 though the vector always boxes x and y, those hints can force unboxing in the expression

1:39 s/force/facilitate

1:39 TEttinger: I'm curious how this performs

1:39 ,(let [sqr (fn [^double d] (* d d)) check-point (fn [] (< (+ (sqr (Math/random)) (sqr (Math/random))) 1.0)) n 10000 total (int-array 1 0)] (dotimes [_ n] (if (check-point)(aset ^ints total 0 (unchecked-inc-int (aget ^ints total 0))))) (* 4.0 (/ (aget ^ints total 0) n)))

1:39 clojurebot: 3.15

1:40 luxbock: justin_smith: what about `gen-point` in bufh's code?

1:40 I get four boxed math warnings which I have no idea how I would eliminate

1:40 TEttinger: also I don't know how I'd type-hint sqr

1:40 justin_smith: luxbock: that shouldn't have any boxed math happening, but it is of course boxing the values

1:41 luxbock: Boxed math warning, blah.clj:3:4 - call: public static java.lang.Number clojure.lang.Numbers.unchecked_minus(java.lang.Object,long).

1:41 TEttinger: so there, the first arg in a subtraction is boxed

1:42 the second is a long already, so no worries about that

1:42 luxbock: ah I see, think I got it now

1:43 yep

1:43 justin_smith: I wouldn't think that (rand) needs a type hint to avoid boxing

1:44 luxbock: it apparently does

1:44 justin_smith: weird, this must be set up wrong...

1:45 oops, wrong clj version in this local repl, don't mind me

1:45 bufh: ok this is another 50% faster https://gist.github.com/singhgurjeet243/208a345c17e8a35fc0be

1:46 justin_smith: bufh: is that just from adding the ^double hints?

1:46 bufh: 2 things: 1. replacing 2 and 1 with 2.0 and 1.0 in gen-point/gen-and-test-point and 2. by adding the two ^double hints

1:47 justin_smith: bufh: (defn gen-point [] [(- (* 2.0 ^double (rand)) 1.0) (- (* 2.0 ^double (rand)) 1.0)]) -- this should help too

1:47 (finally got my own reflection and boxing warning repl opened up)

1:47 funny that rand is not hinted / known by the compiler already

1:48 bufh: ok, only 2 box/un warnings and about the same speed

1:48 justin_smith: luxbock: you were right, I really didn't think rand would be unhinted

1:49 luxbock: is it faster to call (.nth this-vec 0) than `first`?

1:49 justin_smith: luxbock: that would be a good one for a criterium test

1:50 bufh: how do I fix these?

1:50 Boxed math warning, pi/core.clj:24:27 - call: public static java.lang.Number clojure.lang.Numbers.divide(java.lang.Object,long).

1:50 Boxed math warning, pi/core.clj:24:20 - call: public static double clojure.lang.Numbers.unchecked_multiply(double,java.lang.Object).

1:50 justin_smith: bufh: oh, and you can hint gen-and-test-point in the same way - I bet it would speed up even more

1:51 bufh: those two warnings are just the two one-time ops on line 24

1:51 definitely not a bottleneck

1:52 bufh: hmm, so no way of making this code faster?

1:52 justin_smith: (though also very easy to fix with the same kind of type hints we've been doing so far)

1:52 faster rng

1:52 using java data structures instead of clojure ones

1:53 bufh: I've had a lot of vodka and whiskey tonight, there might be other tricks that I would think of in the morning

1:54 bufh: lol, let me not kill the buzz :)

1:54 justin_smith: oh no, it's all good

1:56 Bronsa: cool kids like to get high on clojure

1:59 justin_smith: freenode is where all the cool kids hang out https://twitter.com/stefhatcher/status/641488692809338880

1:59 bufh: thanks for your help - this is the most useful discourse in any #lang group that I have ever been in

2:02 Bronsa: (inc justin_smith)

2:02 gah

2:02 justin_smith: that bot makes clojure look bad sometimes :P

2:04 amalloy: (dec lazybot)

2:04 lazybot: ⇒ 36

2:05 Bronsa: (inc justin_smith)

2:05 lazybot: ⇒ 295

2:23 bufh: ok, so the clojure implementation is only about 50% slower than the java implementation

3:18 luxbock: here is the benchmark game implementation of pi-digits in Clojure: http://benchmarksgame.alioth.debian.org/u32/program.php?test=pidigits&lang=clojure&id=5

3:19 slighly more verbose

3:23 whoa, the Java version of the binary-tree benchmark is actually faster than C or C++

3:35 chomwitt: goodmorning from greece. refer vs require. we can see in repl with ns-map changes we make to the current ns with refer. is there a command to do the same for require ?

4:29 TEttinger: luxbock, that's hilarious. the benchmarks game is really now "who can call an external library written in assembly the fastest"

4:37 tdammers: can I ask questions about Selmer here?

4:46 ddellacosta_: tdammers: I don't see why not...question is more if anyone around now has any familiarity with it

4:46 Bronsa: luxbock: wow that is ridiculous

4:50 quii: Hello, I am a bit of an emacs noob and need some help. I've got quite comfortable using cider and have a *reasonable* workflow for doing TDD. However i really need some refactoring support. The consensus as far as I am aware is to use https://github.com/clojure-emacs/clj-refactor.el . However when I follow the instructions to install it, it seems to just break cider. I get “C-c C-k is undefined” when i try and run my tests. When I

4:50 ..

4:50 So obviously some kind of conflict but I’m not entirely sure where to start

4:50 appreciate any kind of help

4:51 tdammers: ddellacosta_: right...

4:51 quii: yup :p

4:51 TEttinger: quii, it's a bit sleepy right now, stick around and maybe ask again in... 4 hours? that's when east coast US might start getting up

4:51 quii: ok :)

4:51 tdammers: so I'm trying to do {% if somevector|count <= 1 %}

4:52 where somevector is a context variable that I know is a vector

4:52 gives me a NullPointerException

4:52 TEttinger: tdammers: woah what syntax is hat...

4:52 tdammers: TEttinger: selmer

4:53 ddellacosta_: tdammers: no idea how selmer works...but I'll ask some dumb questions to help debug: I'm assuming that that sums the values in the vector? Does it require more than 1 or for no nils to exist in the vector?

4:54 tdammers: the goal is to check whether the vector has 0 or 1 elements, or more

4:54 ddellacosta_: oh, so count is counting the number of items? I see

4:54 tdammers: if it has 0 or 1, I want to generate a hidden field with the only valid value, otherwise I want to render a dropdown

4:54 I tried {% if (somevector|count) <= 1 %}, but that gives me a parser error

4:55 saying that (somevector|count) is not a valid filter

4:55 TEttinger: if it has 0 items, calling ##(seq []) may be trouble

4:55 lazybot: ⇒ nil

4:55 TEttinger: ,(count (seq []))

4:55 clojurebot: 0

4:55 TEttinger: hm

4:55 tdammers: ,(count nil) ; more interesting edge case

4:55 clojurebot: 0

4:55 tdammers: but stil

4:55 l*

4:55 chomwitt: in lein repl (clorure.s[tab] completes with clojure.set clojure.string etc. But i've not loaded them with 'require in the current user namespace

4:56 TEttinger: hm, nope https://github.com/yogthos/Selmer/blob/master/src/selmer/filters.clj#L226

4:56 tdammers: wait, turns out {% if somevector|count <= 1 %} does in fact work

4:57 the exception is caused by something else

4:57 (trial-and-error debugging ftw)

4:57 TEttinger: is the paren thing maybe calling it somehow?

4:57 tdammers: no, if I add the parens, the parser gives a nonsensical error, it doesn't even get to run the template at all

4:57 my guess is that it's a weird edge case in the parser

5:00 TEttinger: hm

5:00 scanning through this... https://github.com/yogthos/Selmer/blob/master/src/selmer/filter_parser.clj

5:00 I can't find any indication that it handles parens sensically

5:00 there's nothing like a grouping indicator

5:01 tdammers: I'd expect it outside of the filter parser

5:01 but haven't found the expression parser yet

5:05 TEttinger: well whatever calls parse is doing something

5:05 eyyyy yogthos

5:05 tdammers has some selmer questions

5:06 https://github.com/yogthos/Selmer/blob/master/src/selmer/parser.clj#L238 tdammers, this looks like the only place it might start to handle parens, and even then it would be something that calls this...

5:06 tdammers: hmm, so far I've been figuring it'd be somewhere in the regexes that deconstruct tags

5:06 util.clj, somewhere

5:07 https://github.com/yogthos/Selmer/blob/master/src/selmer/util.clj#L46

5:07 somewhere around here

5:09 https://github.com/yogthos/Selmer/blob/master/src/selmer/tags.clj#L141

5:09 looks like "if" is special

5:10 so there's not really a notion of "expressions" here, is there?

5:10 that would also explain why binding a seq to a local variable with {% with %} and then trying to iterate over it doesn't work

5:11 TEttinger: I guess? I don't do any web dev that isn't static webpages on github :)

5:12 like the show-off page for the large amounts of art I keep making. http://tommyettinger.github.io/home/PixVoxel/cu3/Firing.html

5:15 tdammers: looks nice

5:15 page locks up firefox somehow though

5:18 TEttinger: hehe

5:18 it's a ton of gifs, it does that

5:18 tdammers: still locked

5:18 and this isn't shitty hardware, mind you - fairly new i7 thinkpad

5:19 TEttinger: it's I believe a firefox bug

5:19 wasamasa: orly

5:19 loads slowly, but surely here in firefox

5:19 TEttinger: there's a page that has even more gifs that you can try wasamasa :)

5:19 http://tommyettinger.github.io/home/PixVoxel/cu3/index.html

5:19 * wasamasa blames TEttinger's OS

5:20 tdammers: uhm, I think I'd rather not :D

5:20 xkill ftw

5:21 TEttinger: I have no trouble with chrome

5:21 wasamasa: it always surprised me when a classmate can't even start chromium without it eating up all the memory and hanging on their L512 while I can use it on my X200s just fine

5:21 TEttinger: L512?

5:21 wasamasa: yeah, at least one generation newer CPU

5:22 mine has a C2D, his an i3

5:22 TEttinger: huh...

5:22 wasamasa: the difference is that I'm using linux and he's got a windows install from work on it :D

5:23 TEttinger: it's weird why some computers can't handle these poorly-made gif spewing pages

5:23 I know someone with a 6-year-old linux netbook who can't load any pages I make with even a quarter that many gifs

5:23 he uses firefox I think for the reason you gave, chromium uses too much mem

5:24 wasamasa: I've got to admit, the second site got quite a bit more for downloading

5:24 * p_l longs for the times when a 50kb webpage was "upper end of what can be linked to without warning about size"

5:24 wasamasa: both peter out on me once in a while

5:24 if it's firefox, it's high CPU usage, for chromium it's a memory leak

5:24 TEttinger: for some reason github hasn't warned me about using more than 1GB of repo space for the github pages repo that hosts all that

5:24 I am using about 4.5 GB now

5:25 tdammers: does git have a space limit?

5:25 TEttinger: github says it recommends staying under 1 GB but does not have a hard limit, and will send a polite email if you use too much

5:26 tdammers: right

5:26 TEttinger: gitlab has a hard 10GB limit for free accounts on their server

5:26 tdammers: which they will probably only start doing once you use an order of magnitude more, or when too many users start doing it

5:26 TEttinger: bitbucket no idea

5:26 tdammers: IIRC bitbucket has no limit at all

5:26 TEttinger: 10 TB, sure

5:26 tdammers: well, no explicit limit

5:27 I bet the fine print has some sort of FUP

5:27 bitbucket price-shapes on team size instead

5:50 Olajyd: Hi TEtttinger :D

5:50 TEttinger: hey Olajyd!

5:50 how's it going?

5:51 Olajyd: TEttinger, going well…had a week off for some job weldone the past few weeks

5:51 TEttinger: good good!

5:51 Olajyd: Yea :)

5:52 TEttinger: back into coding now though?

5:52 Olajyd: TEttinger, Yep..

5:53 Thanks for taking out time to help out, TEttinger

5:54 TEttinger: no worries, it's always a good way for me to keep my clojure skills sharp. I haven't been using Clojure for anything major for a while, these refreshers for you and me help me remember the clojure I want to use for an upcoming thing

6:02 Olajyd: So out of curiorsity, is there any function that can force all prior processing to occur before moving on to the next function?

6:14 TEttinger: Olajyd, I believe there may be, but not for general processing. clojure has a number of tools like this...

6:15 there's futures, which you tell to start running as soon as they are declared, and if they have finished when you later request their return value, you get the return immediately, otherwise, you wait until the future finishes

6:16 the keyword is "blocking"

6:16 futures will block until they can return their final result

6:20 Olajyd: ok

6:23 Thanks TEttinger, so the reason I asked is because soon we’ll be structuring the code base to something like a pipeline, that for one function to run, a prior function mush have finished running

6:24 TEttinger: hm, sounds good. I know there are some things in clojure that are similar to futures, like delays, that you might want to look into

6:25 a step that must be completed to move on might be the body of a future, and you just dereference that future when you need it in the next pipeline step (which blocks until the previous step has a final value)

6:26 I don't know much about the performance of futures and there is likely a better way, though maybe not much better

6:26 Olajyd: uhmmm nice

6:27 will look into that

6:29 TEttinger, I saw this problem in stackoverflow, a function that takes rows: [[“1” “2” “3”] [“a” “b” “c”]] and produces: ([“1” “2” “3”] [“a” “b” “c”])

6:29 is this possible?

6:30 TEttinger: just changing frm [] to () in the outermost?

6:30 ,(seq [["1" "2" "3"] ["a" "b" "c"]])

6:31 clojurebot: (["1" "2" "3"] ["a" "b" "c"])

6:31 TEttinger: ,(seq {["1" "2" "3"] ["a" "b" "c"]}) ; works on any collection

6:31 clojurebot: ([["1" "2" "3"] ["a" "b" "c"]])

6:31 Olajyd: is it possible to have only [“1” “2” “3”] [“a” “b” “c”] without the brackets?

6:31 TEttinger: ah!

6:31 sort!

6:31 sorta!

6:31 Olajyd: heheh :D

6:32 TEttinger: so if you have this within another function, there's kinda a way

6:32 but there's no way to do multiple returns

6:32 Olajyd: hmmm great

6:32 * oddcully is having a deja vu again

6:33 TEttinger: ,`(map str ~@[["1" "2" "3"] ["a" "b" "c"]])

6:33 clojurebot: (clojure.core/map clojure.core/str ["1" "2" "3"] ["a" "b" "c"])

6:33 Olajyd: oddcully…deja vu? lol

6:33 TEttinger: which would need to be in a macro or be eval'ed

6:33 Olajyd: hmm

6:33 TEttinger: ,(apply map str [["1" "2" "3"] ["a" "b" "c"]])

6:33 clojurebot: ("1a" "2b" "3c")

6:33 TEttinger: might be what you want

6:34 apply can remove the first layer of nesting from a collection

6:36 Olajyd: lol its a function assigned to my colleague though..I’m not very clear with his story on homw to implement it though..wanted to help out but..I’ll just set him up on IRC so he can ask himself

6:37 TEttinger: a clojure function can only return one value. that value could be 1, could be "hello", could be [[1 2 3] [:a :b :c]]

6:39 Olajyd: TEttinger, I’m sorry i dont understand what side effects mean in clojure functions :(

6:39 TEttinger: a clojure function can only return one value. that value could be 1, could be "hello", could be [[1 2 3] [:a :b :c]]

6:40 you can have side effects, which are things like changing an atom and then returning some other result unrelated to the atom

6:40 Olajyd: ok

6:40 TEttinger: one way to get two results out of a function is to have two side effects :)

6:41 Olajyd: ok

6:41 lol…nice, gotcha :)

6:41 TEttinger: ,[(def res1 (atom []))(def res2 (atom []))]

6:41 clojurebot: [#'sandbox/res1 #'sandbox/res2]

6:42 TEttinger: ,(defn side-effecting [n] (do (swap! res1 conj n) (swap! res1 conj (inc n)) (* n n n)))

6:42 clojurebot: #'sandbox/side-effecting

6:42 TEttinger: ,(side-effecting 1)

6:42 clojurebot: 1

6:42 TEttinger: ,(side-effecting 2)

6:42 clojurebot: 8

6:42 Olajyd: hmmm

6:43 TEttinger: ,[@res1 @res2]

6:43 clojurebot: [[1 2 2 3] []]

6:43 TEttinger: oh haha

6:43 I was adding to res1 both times

6:43 ,(defn side-effecting [n] (do (swap! res1 conj n) (swap! res2 conj (inc n)) (* n n n)))

6:43 clojurebot: #'sandbox/side-effecting

6:43 TEttinger: ,(side-effecting 20)

6:43 clojurebot: 8000

6:43 TEttinger: ,[@res1 @res2]

6:43 clojurebot: [[1 2 2 3 20] [21]]

6:43 ane: is refactor-nrepl broken with clojure 1.7?

6:44 travis builds seem to be failing

6:44 Olajyd: :)

6:44 Rurik: Why is swap! named swap! ?

6:44 TEttinger: the ! is so you know it isn't safe to call during a transaction IIRC

6:44 nooga: because oit swaps the value?

6:45 Rurik: nooga, I meant ! part

6:45 nooga: oh

6:45 TEttinger: I believe it's the transaction reason

6:46 Olajyd: yeaa hmm interesting what is the difference between the .swap and swap!?

6:46 TEttinger: I don't think there's a .swap that you're expected to use?

6:46 Olajyd: ok

6:46 TEttinger: that would be calling the java API which I guess you could do... but it wouldn't have a lot of clojure benefits

6:47 when I say java API

6:47 I meant the java that clojure for the JVM is coded with

6:47 and that's not the same as the standard java lib that clojure often should use, like for strings

6:48 Olajyd: gotcha

7:02 jaaqo: I think it read somewhere appending ! to a function name is to say this function has side-effects please be careful

7:04 ane: does evaluating the t/ann form of core.typed run the type checker?

7:05 oh. no it does not.

7:23 Olajyd: I have a compare function to get the maximum value, (reduce #(if (pos? (compare % %2)) %1 %2) [[" " "2009/12/02"] ["4" "2005/02/08"] ["0" "2014/12/02"] ["5" "2005/08/01"] ["2" "2007/09/02"]]) ;=>["5" "2005/08/01”] but I want to go the comarison based on column 1, to give ;=> ["0" "2014/12/02"]

7:24 ,(reduce #(if (pos? (compare % %2)) %1 %2) [[" " "2009/12/02"] ["4" "2005/02/08"] ["0" "2014/12/02"] ["5" "2005/08/01"] ["2" "2007/09/02"]])

7:24 clojurebot: ["5" "2005/08/01"]

7:24 tdammers: another selmer question: I need to iterate over a list of things, and use the current iteratee as an index into another thing

7:24 something like:

7:25 {% for item in items %}{{ descriptions[item] }}{% endfor %}

7:25 except that Selmer doesn't have that kind of syntax

7:25 I tried creating a "lookup" filter, such that I could write:

7:25 {{ descriptions|lookup:item }}

7:25 but it only works when I pass a string literal

7:26 I can't seem to pass the second argument to that filter from an iteration variable

7:26 Olajyd: TEttinger, you there?

7:27 tdammers: oh crap, my custom filter gets passed the string "item"

7:31 I think it's time to find a better template library

7:32 oddcully: Olajyd: don't compare the whole vector but only the second element

7:37 Olajyd: yeaa

7:38 oddcully any ideas on how to do that?

7:38 oddcully: destructuring, `second`

7:39 Olajyd: in the compare function?

7:40 oddcully: this is where you find out, what the smaller/larger item, right?

7:40 s/what/&s/

9:28 dstockton: is there a debugger that can work with vim/fireplace that anyone has had success with?

9:28 i tried cider but i couldnt get it to play nicely with evil

9:29 ane: what problems did you have with evil and cider?

9:42 chomwitt: we can see in repl with ns-map changes we make to the current ns with refer. is there a command to do the same for require ?

9:43 justin_smith: chomwitt: ns-refers iirc

9:45 no, that's not it

9:46 chomwitt: ns-aliases works if you used :as when requiring

9:47 otherwise, just the fact that another ns required does not change your own ns (of course a refer changes ns-map)

9:51 visof: hi guys

9:51 how can i do this haskell using clojure? take 10 (iterate (2*) 3) ?

9:51 dstockton: it just wasnt instrumenting right ane, i think the shortcuts are often conflicting

9:51 visof: [3,6,12,24,48,96,192,384,768,1536]

9:51 justin_smith: ,(take 10 (iterate (partial * 2) 3))

9:51 clojurebot: (3 6 12 24 48 ...)

9:52 visof: justin_smith: what partial do?

9:52 dstockton: evil just makes me uneasy and i dont like the default emacs shortcuts

9:52 justin_smith: visof: it's a pathetic, weak, incomplete, disappointing substitute for currying

9:53 visof: but since we have varargs, it's pretty much the best we can get it seems :P

9:53 chouser: wow. I wasn't even sure automatic currying was a good idea.

9:54 justin_smith: chouser: I miss it so much :P

9:54 chouser: visof: (patial * 2) is basically the same as (fn [x] (* 2 x))

9:54 justin_smith: from?

9:54 justin_smith: chouser: ocaml, and it's (fn [& args] (apply * 2 args))

9:55 ,((partial * 2) 3 4)

9:55 clojurebot: 24

9:55 chouser: yes, less "basically", but yes. :-)

9:56 visof: justin_smith: chouser thanks guys

9:56 can i do composition of functions in clojure?

9:56 justin_smith: comp

9:56 ,((comp inc inc inc) 0)

9:56 clojurebot: 3

9:56 visof: thanks

9:58 justin_smith: chouser: I only exaggerate my disappointment with partial because I've had people try to tell me partial was the same as currying (which of course it isn't)

9:58 chouser: righto

9:58 justin_smith: "I miss currying now that I do clojure" "but partial is currying" "..."

9:59 chouser: auto currying and succinct composition are nice for golfing in IRC, but the Clojure code I've been in for the last several months would I think have only been worse if auto currying were used

10:00 if (foo a b c d e f) invokes foo but (foo a b c d e) invokes nothing and returns a fn, slightly mystifying code would be even harder to comprehend.

10:01 justin_smith: chouser: yeah, currying was just an idiom I missed, but the idiom makes little sense without strong typing, and varargs are a nice tradeoff in the end

10:01 because yeah, with clojure's version of type enforcement the errors would be very hard to track down

10:02 chouser: yeah, I can see that static typing would help reduce the errors between the original code author and the computer

10:02 ...but subsequent human readers might still have unnecessary difficulty following along

10:03 I say "unnecessary" because partial, which is just as good as currying.

10:03 * chouser ducks

10:03 justin_smith: :P

10:03 I can almost accept "just as good", given the other trade offs, it's "is the same as" that sets me off

10:04 mungojelly: typing and testing both seem to me like basically the same strategy: have two versions of the code so they can check each other

10:05 justin_smith: mungojelly: they also act as documentation - making things explicit that can easily be ambiguous in clojure code

10:06 tdammers: the main difference is that tests are blacklists, types are whitelists

10:06 mungojelly: i really don't understand why we don't use any strategies that match more than two things? maybe because we're too lazy even to do two, usually. :/

10:06 tdammers: (only really works when everything is typed though)

10:07 justin_smith: I wish I could get my team to do tests or data types. At least one of those. Hell, I'd settle for some assertions in the code at this point :P

10:08 Bronsa: puredanger: why is CLJ-1809 no longer in the 1.8 list? it's a serious regression caused by the direct linking changes

10:11 oddcully: justin_smith: lead from the front ;P

10:12 justin_smith: oddcully: I write tests and use schema. And then I end up needing to deal with accusations that I'm wasting my time doing so.

10:12 I'm not the lead

10:16 snowell: Getting management to look past RIGHT NOW and see the value of testing is way harder than it should be

10:16 mungojelly: does clojure have yet one of those cute things where you put a test in the form of a transcript in the doc string

10:16 justin_smith: you can attach a test as metadata to a function, in practice most of us prefer putting tests in their own namespace

10:19 tdammers: common problem: management prefers irrelevant quantifyable metrics over relevant unquantifyable metrics

10:19 Bronsa: (inc tdammers)

10:19 lazybot: ⇒ 1

10:20 justin_smith: (inc tdammers) that's about it

10:20 (inc tdammers)

10:20 lazybot: ⇒ 2

10:20 tdammers: I think this happens more often the deeper an organisation's hierarchy

10:21 with deep hierarchies, almost all managers are somewhere in between the adjacent levels

10:21 so they have to somehow make it such that whatever their subordinates do, they can produce quantifyable evidence that it wasn't their fault

10:23 mungojelly: conversely, is our intuition true that making coherent stuff that does what we want is what's important, lots of people seem to be profiting off code that just does some unpredictable something, maybe that's exciting

10:26 sobel: it is exciting

10:26 just..not in the good way

10:28 tdammers: something about local optima

10:28 justin_smith: mungojelly: in practice, without some kind of typing and/or testing and/or docs you end up with an unmaintainable system

10:29 nobody knows how to work on anyone else's part of the code base

10:30 you can't make large scale changes because too many things break, without any indicators of what your root causes of the bugs are, or where the real error is happening

10:30 mungojelly: i can accept that economic pressures make most code crap but also shouldn't there be some good code somewhere also, maybe just for fun, sigh

10:30 tdammers: there is plenty of good code in the world

10:31 mungojelly: justin_smith: but everybody knows that and they still tell us to make unmaintainable brittle systems, are they really getting it wrong or are supple systems more cost than they're worth

10:32 tdammers: can you recommend a project in clojure i should read? i need to read some good code that makes me feel better about the world

10:32 justin_smith: mungojelly: when the brittleness forces a full rewrite (which I have seen plenty of times) I take that as a sign that suppleness would have been worth it - building it supple once is easier than building from scratch twice

10:33 I've worked on plenty of clojure projects that wouldn't have happened if the ruby code that preceded it had been more supple

10:34 tdammers: mungojelly: haven't been doing enough clojure to suggest anything here, but there should be plenty

10:35 mungojelly: I could recommend a bunch of Haskell projects...

10:42 mungojelly: i've been really annoyed as i've tried to learn to program by the absolute lack of simple interfaces to anything, it's very difficult to learn when nothing at all is simple, and i'm convinced there's no good reason at all

10:43 here's my first attempt at throwing a ladder back down to my fellow newbies: working title "7by7grid" it's an interface where what you pass around is lists of 49 RGBA colors

10:44 sobel: when i worked in a ruby shop i saw a lot of OO development

10:45 mungojelly: so then to make a piece that participates in that interface you just have to print out like 00000000 FFFFFFFF repeat for a while and it shows black and white stripes, etc., it goes right from print hello world to printing something pretty

10:45 sobel: they talked about FP but i only saw the clojure developer(s) doing it

10:45 visof: ,(take 10 (rest (iterate (partial * 2) 3)))

10:45 clojurebot: (6 12 24 48 96 ...)

10:45 visof: ,(rest (iterate (partial * 2) 3))

10:45 clojurebot: (6 12 24 48 96 ...)

10:46 visof: (rest (iterate (partial * 2) 3)) guys this expression will return lazy too?

10:46 mungojelly: most of the functional programming i've seen is basically the same shape as OO anyway, instead of "objects" there's "data" and instead of mutation there's the "next version" of the data

10:54 puredanger: Bronsa: just ticket juggling for Rich

10:55 He wanted 1805 and 1809 at the top of a list somewhere and this was easiest

10:59 sobel: mungojelly: sounds good to me. i regularly find pure functions much easier to debug and to compose.

11:01 mungojelly: sobel: yes they work better even if what you're writing in them is a translation of an OO feeling, you can more easily put time travel in because you're more um in control of the data. but so rarely do i feel like the programs i'm reading actually feel functional at heart.

11:02 like in a book about functional programming there's this beautiful ahhhhh quality to it, and then real life "functional" programs are always mostly really just poking slowly with sticks at piles of data

11:04 they have god objects, except they're smashed apart into a god pile of data and a god associated set of functions-- which is what an object is, if you think about it

11:04 sobel: ok, i have no idea what you're talking about or trying to do

11:04 i make things that work and it's easier in clojure

11:05 mungojelly: you'd think if you went to any even moderately large funcitonal program you'd find in there lots of awesome functions that do useful things, which you could then take out and compose into different programs, but no, it's a function like do-specific-thing-to-only-my-pile-of-data

11:06 sobel: o_O

11:07 i can't share your offense that application code is meant for one application, especially when it's built in clojure. the data structures make application core dev pretty easy already.

11:08 other languages need lots of (reusable) glue to make them modular, but with lisps you just get right to business because the language provides plenty of glue

11:09 mungojelly: obviously at some level you have your application specific code, but it would be nice if it were using parts that are as general as possible so everyone else could pick them up and do something else with them

11:10 sobel: have you perused clojars?

11:10 mungojelly: only a little so far! do you have any particular recommendations?

11:11 sobel: most of the community uses leiningen which resolves depedencies through maven repositories, clojars being the main community clojure module repo

11:12 mungojelly: yeah i've used leiningen to install a few things and clojars was where they came from

11:12 sobel: ok, so if you're looking for a library, search "<topic> clojars" and you should end up in a useful spot

11:14 that may be why you're not seeing library code in applications.

11:28 Leonidas: mungojelly: I kinda disagree that typing and testing is the same, because typing is not really a second version of your code.

11:29 mungojelly: Leonidas: yeah it's not another version of the same thing, but it's another related program, a similar but much vaguer program that just says which thingies can flow where

11:30 Leonidas: mungojelly: yeah, kind of.

11:30 the vagueness is depending on your type system, ranging from untyped to hmm, dependently typed.

11:30 mungojelly: are there any other things in that pattern? like, other versions of your code that you prop it up with. documentation, except if it's only written for humans no one checks it apparently. :/

11:31 Leonidas: generative testing?

11:33 mungojelly: i've watched like three talks about generative testing now and it sounds cool but i haven't actually used it yet

11:33 Leonidas: depending on the problem it can be quite awesome.

11:34 mungojelly: yeah it doesn't actually fit the problem i'm working with. maybe i should make myself a better problem.

11:36 i like evolving code and there you get selection, which is similar to testing but less absolute, you can test a variety of things and score them on a curve rather than just pass/fail

11:37 sobel: i wouldn't like to use code that is tested on a curve

11:37 if i need a use case to work, i'd like its unit test to pass

11:37 deiodeiodeio: I'm using an external library with obscenely verbose logging (through clojure.tools.logging). How do I adjust its log level?

11:38 mungojelly: sobel: well it depends on what it's for, but you can do both, you can say absolutely fail if you don't pass these tests, also i grade you on how fast you did them

11:39 sobel: performance is pass-fail to me, too

11:41 that said, performance is often great, but i know where my risk areas are from experience

11:41 mungojelly: profiling you break it down and make variations in a quality and inquire, which one runs better. generally people seal it back up and put the "better" one as the one it does, done. another perspective is to keep both possibilities and let it find for itself which one is better, then it can adjust if the "better" path turns brittle.

11:42 deiodeiodeio: :(

11:43 mungojelly: i'm astonished by all this code that only knows one way to do each thing. of course it falls over often, there's no understudies for anyone.

11:43 sobel: deiodeiodeio: check the docs of the library you used

11:43 mungojelly: not sure what you're talking about. my database has a smart execution planner for queries but everything else doesn't need that kind of complexity.

11:44 deiodeiodeio: sobel: the library does not provide any facilities for setting log levels

11:44 sobel: deiodeiodeio: get a better one?

11:44 deiodeiodeio: er, there is just one

11:44 sobel: there's only one logging library for clojure?

11:44 deiodeiodeio: what, no, read what I wrote again

11:45 the library I'm using uses clojure.tools.logging

11:45 liberally

11:45 and I want to shut it up so I can see my output

11:45 preferably without writing any log4j files

11:46 snowell: I have a physical reaction to seeing log4j/slf4j anymore. No other library produces breaking API changes and incompatible versions like they do

11:47 deiodeiodeio: yeah me too

11:47 sobel: looks like i went with timbre

11:48 and it has a set-level! function that takes reasonable values like :info

11:48 deiodeiodeio: however, it doesn't seem like clojure.tools.logging exposes any methods of setting verbosity: https://clojure.github.io/tools.logging/

11:49 yeah, with timbre I would jut re-bind *config* and it would be fine

11:49 sobel: the only thing that threw me for a loop with it was it used a background logger, which required i call (shutdown-agents) to exit smoothly

12:00 deiodeiodeio: anyone? it seems like it shouldn't be hard, but I'm kind of stuck here

12:00 justin_smith: deiodeiodeio: clojure.tools.logging is just a frontend to the java logging stuff - it doesn't have anything for setting log levels, I think you'll need to make a .properties file

12:01 or a log.xml, or whatever

12:02 deiodeiodeio: the README for clojure.tools.logging has a 5 line log4j.properties you can copy/paste, the first line sets the output level

12:02 https://github.com/clojure/tools.logging

12:03 deiodeiodeio: justin_smith: yeah, thanks.. I would just rather not pollute my project with log4j files just because a library I'm using uses it

12:04 justin_smith: deiodeiodeio: they made that decision already - unless you know an alternative that doesn't use log4j, that's where you are at

12:04 deiodeiodeio: actually, (with-redefs [clojure.tools.logging/log (fn [& args])] (call-to-external-library)) seems to work :)

12:04 justin_smith: oh man that's evil

12:06 rhg135: Isn't log usually a macro?

12:07 justin_smith: rhg135: in this case it is one, yeah https://github.com/clojure/tools.logging/blob/master/src/main/clojure/clojure/tools/logging.clj#L69

12:08 now rebinding log* I could see working with with-redefs, but I am surprised rebinding log would work

12:09 deiodeiodeio: yeah, that would make it problematic

12:09 justin_smith: deiodeiodeio: log calls log*

12:09 but I still think configuring the lib is better than monkey punching it

12:09 deiodeiodeio: rebinding log worked it the repl.. rebinding log* seems to work regardless

12:10 rhg135: Me too, justin_smith

12:10 deiodeiodeio: justin_smith: sure, but I refuse to give up now

12:10 justin_smith: be careful, monkeys throw poop if you get them mad enough

12:11 deiodeiodeio: hah

12:11 rhg135: Monkey punch is a phrase I have not heard in this context

12:11 justin_smith: rhg135: it's a less innocuous rephrasing of "monkey patch"

12:12 rhg135: because you are doing something violent to the other code, not just altering it

12:12 mdeboard: What's the difference between "parking" and "blocking" wrt <! vs. <!! in core.async

12:13 justin_smith: mdeboard: whether the thread is allowed to do other work while your condition waits

12:13 mdeboard: Will it read from the channel when there is something available?

12:13 justin_smith: mdeboard: with parking, the thread that was running your code can be reallocated by core.async to do other work

12:13 rhg135: Yeah, I'd say rebinding a macro name to a function is very bad

12:13 justin_smith: mdeboard: in both cases your thread resumes execution when data is available, the difference is what is done with your resources while waiting

12:14 mdeboard: Aha thanks justin_smith

12:14 mungojelly: is the convention here both macros and functions are spelled all lower case? is there some reason they should look the same?

12:14 justin_smith: mungojelly: upper case is for Classes

12:14 (not by restriction, but by convention)

12:15 mungojelly: in lisps functions and macros have always looked the same, as long as the two have existed

12:16 mungojelly: is it for a reason though? intuitively i feel like maybe it could be useful to macro-ify something that's already a function to change existing code, so i guess it's consistent with that

12:16 mdeboard: Sorry for this stupid question but I'd need to use like `(go-loop [] (do-stuff (<! my-channel)))` to read from the channel in a loop right?

12:17 justin_smith: mdeboard: well, for that to actually loop you would need a call to recur somewhere

12:17 mdeboard: (throw a `recur` in there)

12:17 yeah

12:17 lol

12:17 justin_smith: right, yeah, that is pretty much it

12:18 mdeboard: Ok cool

12:19 justin_smith: mungojelly: it's a convention dating to at least the '60s if not the '50s. I don't know if there is a lot of discussion since then even? I can see a rationale for wanting the difference between special-form, macro, function to be clear though

12:19 mungojelly: i wasn't born then but from what i've seen i seem to remember it being ALL CAPS ALL THE TIME at first for a while

12:19 sobel: from a tooling perspective i don't want them to be different

12:19 justin_smith: mungojelly: of course in C where macros have totally different compilation rules and can make whitespace changes totally break your code, UPPER_CASE_MACROS() are needed

12:20 mungojelly: right, they were case-insensetive, but there was no naming convention that separated special-forms, macros, and functions

12:21 mungojelly: I had generalized from "upper case" to "any sort of typographical distinction"

12:25 mungojelly: the early naming conventions in lisp do make it pretty clear they expected you to look up and memorize what every symbol means, nothing about them is guessable, they're not mostly even ordinary words

12:25 justin_smith: mungojelly: unlike C, lisp style macros don't have lexical gotchas (they don't transform code on a string manipulation level) and while you have to watch out for using them in invalid ways (eg. they are not functions you can pass to a higher order function, they bind values at compile time) the errors won't be nearly as bizarre if you get it wrong

12:26 mungojelly: justin_smith: i do understand that in theory but it slips my mind how macro hygiene actually works, does clojure like put a random number at the end of the real name of all your stuff?

12:27 justin_smith: mungojelly: we don't have actual hygeinic macros, but the ` (syntax-quote) reader-macro does namespace qualify symbols and forces you to use gensyms for new bindings

12:27 which in practice eliminates 98% of the accidental capture problems

12:28 mungojelly: oh hmm namespace qualify, that makes sense because i've noticed in clojure it's very consistent everything gets namespaced

12:28 justin_smith: '`(foo)

12:28 ,'`(foo)

12:28 clojurebot: (clojure.core/seq (clojure.core/concat (clojure.core/list (quote sandbox/foo))))

12:28 justin_smith: it's verbose, but note how an explicit namespace was added

12:28 makes capture much less likely

12:29 mungojelly: ok i see, and that's a good-enough replacement for that actually ideal hygiene algorithm that's complicated enough to have slipped my mind

12:30 clojure in general seems very practical

12:31 justin_smith: mungojelly: I re-learned syntax-quote and syntax-case so many times and they still haven't stuck

12:32 (that is, the scheme version)

12:32 err s/syntax-quote/syntax-rules

14:10 mdeboard: Anyone have any guidance on why this function is not writing to a file but instead returning the `chan`? https://gist.github.com/mattdeboard/431ef638ba64848d247c

14:11 justin_smith: mdeboard: with-open closes the file on exit, go-loop exits immediately and does its thing in another thread, and returns a chan

14:11 s/file/writer

14:11 closes the writer on exit

14:12 mdeboard: I see, should I be opening the file inside the go-loop?

14:12 justin_smith: so what's happening is that the writer is being closed before the code in the go-loop even runs

14:12 mdeboard: Oh, weird.

14:12 ok

14:12 justin_smith: no, because then it would close before you run the next loop cycle

14:12 mdeboard: Can I pass the open file as a variable

14:12 in the `loop` call

14:12 justin_smith: and go loops don't work with the paradigm of with-open

14:12 mdeboard: `go-loop`

14:12 Ahhh

14:12 Ok. Huh.

14:12 So jus tmanually open/close

14:12 justin_smith: since the task can pass between multiple threads etc.

14:12 yeah

14:13 mdeboard: Mmkay

14:13 amalloy: justin_smith: i don't see why that's a problem. you can't use go-loop, but you can use go

14:13 (go (with-open [...] (loop [...] ...)))

14:13 justin_smith: yeah, I would use lexical closure to access the writer, and then have a task that reads the return chan of the go-loop then immediatly closes and cleans up

14:14 hmm - and that works despite the parking and such that go is doing?

14:14 amalloy: of course. that's what go is for, making stuff look sequential

14:14 with-open is just a let and a try/finally, and you know those work

14:15 justin_smith: amalloy: I guess I expected some weird interaction between the with-open block and the go block, but if they work together, that's handy

14:15 amalloy: it's not like the FileOutputStream or whatever cares what threads are writing to i

14:15 t

14:15 mdeboard: Hm

14:16 amalloy: i mean, in fairness i have never tried any of this. but based on how i understand these things to work i would be fairly surprised to be wrong

14:16 mdeboard: amalloy, https://gist.github.com/mattdeboard/c566cf94a9e510cf86d6 doesn't seem tow ork

14:16 justin_smith: mdeboard: what exactly fails?

14:16 mdeboard: There's just no writing to the output file

14:17 amalloy: mdeboard: try something simpler. write some fixed characters to a file

14:17 justin_smith: mdeboard: there's no control flow in your code that would cause that loop to exit and thus let the with-open close the writer

14:17 mdeboard: instead it will sit there and wait for more messages, not letting the with-open shut down

14:17 mdeboard: ok yeah that works

14:18 justin_smith: so perhaps read until the channel is closed

14:18 or until you get a magic ::flush value

14:18 or whatever

14:24 amalloy: so that actually works, right? it writes things?

14:24 mdeboard: amalloy, Yep just was a bomb because I'm an idiot and didn't ever exit the loop -_-

14:24 In my defense I'm on a phone conference.

14:24 amalloy: okay that's fine. it's just i was trying to prove it to myself locally and never really use core.async so i am doing stuff wrong

14:25 like i expected https://www.refheap.com/35a77d388881dec359d7174c9 to work but apparently it doesn't

14:26 justin_smith: amalloy: my concern is the try/catch of the with-open making any sense when you have parking inside

14:26 amalloy: justin_smith: go's rewriting code addresses try/catch i'm fairly sure

14:26 justin_smith: OK

14:26 amalloy: why would you worry about try/catch and not about, say, let or loop?

14:26 those are all equally as squirrely

14:26 justin_smith: hmm...

14:27 amalloy: or even about function calls, like (println (<! ch))

14:27 mdeboard: Sadly I use clojure so rarely nowadays I remember precious little :(

14:28 justin_smith: amalloy: I am familiar with let bodies that have multiple threads inside seeing their bindings, for example, but I have no existing model for a try/catch that jumps across thread boundaries

14:28 though I admit a park inside the binding vector is weird to me conceptually as well

14:29 amalloy: well, it't not really multiple threads, of course. it's one thread at a time, possible totaling more than one thread

14:29 justin_smith: right, but even the one at a time thing interacts oddly with my mental model of try/catch, though this is probably just exposing my ignorance

15:16 mdeboard: Gosh darnnit I do not understand D:

15:19 Bronsa: puredanger: wrt your tweet, do you want a ticket concerned with just making `satisfies?` faster or with moving the cache from the method level to the protocol level as I suggested as a possible solution?

15:22 uptown: does anyone know whether core.async pub/sub subscribers need to be explicitly unsubscribed from their topics or just close!d to remove them?

15:22 and, i suppose, whether publishers clean up internally afterwards?

15:25 there's no doc coverage anywhere that i can find

15:30 mdeboard: amalloy, justin_smith, turns out using an exception was being swallowed, presumably because of the goroutine, in my usage of `apply`

15:31 justin_smith: mdeboard: full discussion of that "swallowing" http://stuartsierra.com/2015/05/27/clojure-uncaught-exceptions

15:31 mdeboard: tl;dr: that's what java does by default for exceptions not in your main thread, you should explicitly use try/catch

15:31 mdeboard: Nice

15:31 Perfect, thanks.

15:32 Here's the working form https://gist.github.com/mattdeboard/c566cf94a9e510cf86d6

15:32 original seen https://gist.github.com/mattdeboard/c566cf94a9e510cf86d6/revisions

15:33 justin_smith: mdeboard: nice, and the .flush is a good touch too

15:33 mdeboard: I learned it by watching you, alright?

15:33 but seriously you mentioned flushing and it made sense

15:34 justin_smith: ahh, right

15:38 mdeboard: Stupid quesiton probably

15:38 but calling bufferedWriter.flush() clears the buffer right?

15:39 justin_smith: I would expect that, but I don't have proof handy.

15:41 mdeboard: I'd expect it too but I'm getting some unexpected results

15:42 I don't think it does no

15:45 amalloy: justin_smith: well, by default clojure prints uncaught exceptions to the console

15:45 er, java does

15:45 it's *clojure* that makes those messages hard to find

15:45 justin_smith: amalloy: as the article says, in the main thread, not in other threads

15:46 I've had (especially core.async) threads just swallow expections with no printing, exactly as stuartsierra describes

15:46 *exceptions

15:46 amalloy: that has not been my experience in java, and i remember core.async at one point had a (try (do-your-stuff) (catch Exception e)) or something very like it

15:46 but i could be remembering something wrong

15:48 justin_smith: amalloy: (do (.run (Thread. #(fn [] (Thread/sleep 10000) (/ 1 0)))) nil) ; won't work in a bot, of course

15:48 amalloy: that will print nothing

15:49 amalloy: justin_smith: for example, try (doto (Thread. #(throw (Exception. ""))) (.start))

15:49 it doesn't print anything in your repl buffer in emacs, but it *does* go to stdout, which is lein's process

15:49 justin_smith: ahh, my example above was broken

15:50 amalloy: (and you can see that if you look at the *swank* buffer, or *nrepl* or whatever)

15:50 justin_smith: yeah

15:50 amalloy: Exception in thread "Thread-11" java.lang.Exception: at user$eval2239$fn__2240.invoke(c3f4f6ddbaf4ac46782f4c04098f05de409d4881-init.clj:1) at clojure.lang.AFn.run(AFn.java:22) at java.lang.Thread.run(Thread.java:745)

15:50 justin_smith: I'm just using a terminal, you are right

15:51 amalloy: anyway, i think the default uncaught exception handler *is* to print to stderr, but a lot of clojure programs don't make it easy to see stderr

15:51 so i don't really approve of blaming that on java

15:53 justin_smith: amalloy: yeah, I just double checked and I also get the stack trace in a vanilla java -jar repl

15:53 amalloy: so clearly something stuartsierra is blaming on java is actually happening in clojure land (maybe core.async related) because I have definitely seen the behavior he is talking about there...

15:53 amalloy: yes

15:53 xemdetia: its a shame the jvm doesn't give you some sort of namespace to output file pipe without some weird logging lib

15:54 justin_smith: xemdetia: you can do it with timbre (dunno how timbre rates on the weird scale for you though)

15:56 xemdetia: justin_smith, it does look good for new stuff but I have a lot of drunk ponies I am leading around with log4j already :(

15:56 I will have to make a note

15:58 amalloy: justin_smith: the catch in https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async.clj#L885 is a fun one

15:58 but probably not the issue in this particular case

16:00 justin_smith: amalloy: odd, I see the map function but no try at that link

16:01 amalloy: errr, scroll down a bit? it's right there

16:02 justin_smith: oh, duh

16:02 amalloy: https://github.com/clojure/core.async/blob/master/src/main/clojure/clojure/core/async.clj#L462 is another suspicious customer. if i do something equivalent to this uncaught business in my repl, nothing prints to the repl but only to lein's stderr

16:02 (this is probably lein's fault, or nrepl's, rather than core.async's, since i don't think core.async can really do any better)

16:03 mdeboard: What's this syntax doing? `(let [{deletes :in-chan} (some-chan-generating-func)])`

16:03 specifically the map

16:03 as the first binding for let

16:04 Is it some kindof map-deconstructing bind?

16:05 destructuring bind*

16:05 justin_smith: mdeboard: destructuring

16:05 yes

16:05 ,(let [{a :a} {:a 42}] a)

16:05 clojurebot: 42

16:06 justin_smith: ,(let [{{{c :c} :b} :a} {:a {:b {:c 42}}}] c)

16:06 clojurebot: 42

16:08 justin_smith: ,(let [{{{[one two three] :c} :b} :a} {:a {:b {:c [41 42 43]}}}] two)

16:08 clojurebot: 42

16:08 justin_smith: perhaps destructuring would be more pleasingly consistent if it grabbed items from sequences backwards

16:15 devn: With defrecords you can add arbitrary key value pairs

16:16 How does this affect performance, if say you have 5 fields specified in the record definition

16:16 and you add tack on an additional k/v pair

16:16 where the field is not specified

16:17 justin_smith: devn: the fields defined for the record are still (incrementally) faster, unless you dissoc one of the defined keys, then you get a vanilla map back iirc

16:17 amalloy: devn: there's an extra implicit field named __extmap, which is just a map of all the non-basis keyvals specified for this instance

16:17 do you? i thought you just couldn't do that

16:17 ,(defrecord Foo [x])

16:17 clojurebot: sandbox.Foo

16:17 amalloy: ,(dissoc (Foo. 1) :x)

16:17 clojurebot: {}

16:18 amalloy: ,(class (dissoc (Foo. 1) :x))

16:18 clojurebot: clojure.lang.PersistentArrayMap

16:18 amalloy: huh. has it always been that way?

16:18 justin_smith: amalloy: as long as I remember

16:18 I recall Bronsa complaining about some annoying consequences of this for his project

16:22 Bronsa: amalloy: yeah it has

16:22 justin_smith: no, no, my issue was a bug with record literals, which is fixed in 1.8

16:23 justin_smith: oh, cool

16:23 Bronsa: which I noticed yesterday actually caused a bug in scheme a while ago

17:20 kavkaz: I have a function which requires several functions I defined myself. I probably won't be reusing them elsewhere. Right now I have them defined with letfn. Is it better to define them with defn or just keep it this way and not have any of them in the namespace?

17:21 I read somewhere, perhaps in a book that you should use anonymous functions (or functions of that nature) within a function and not pollute the namespace

17:21 but I'm not sure if it's idiomatic to have long Clojure functions

17:21 justin_smith: kavkaz: I'd call that a style choice.

17:22 kavkaz: a compromise would be a top level letfn (though that would be weird), or use defn- to make private definitions

17:22 blake_: Testing is easier if you let them pollute the namespace.

17:24 justin_smith: blake_: that's true, but I usually prefer the thing where tests cover what you expose publicly, rather than testing all the internals

17:25 then again lately I'd settle for tests existing at all :P

17:25 blake_: justin_smith: That's--hah--probably a good clue, though, I think: If it's something you need to test, maybe it's not a good idea to bury it.

17:26 justin_smith: very good point

17:27 kavkaz: justin_smith: I see.

17:27 The thing is that the three functions are in a top-level letfn

17:27 justin_smith: kavkaz: another consideration is that fp and oo sometimes have different philosophies about what is hidden and why

17:27 kavkaz: I might as well just define them with defn

17:27 Ah I see

17:28 justin_smith: like in fp you want to be able to hide your implementation details so consumers don't break a data structure abstraction, but expose state

17:29 so it might be OK to expose functions (as long as they preserve your key data structure abstractions)

17:29 kavkaz: justin_smith: Interesting, I kind of get what you're saying. Can you give me an example?

17:30 justin_smith: kavkaz: if you implemented an immutable data structure, but had a setter method that mutated it for performance reasons, I would hide the setter

17:31 if you have a helper function that doesn't break your data abstraction, but simply implements part of your implementation logic, that's not as bad to expose

17:31 as long as that helper doesn't allow mutation of some sort, or breaking some other invariant your lib assumes / exposes

17:31 kavkaz: justin_smith: Ah I see, that makes sense now

17:32 Honestly these functions are just part of a large procedure.

17:32 justin_smith: kavkaz: given that we are using immutable data for most things in clojure, we don't have to be quite as careful about hiding things - the damage a misbehaving client can do is reduced

17:32 kavkaz: yeah, I figured, that's the normal thing in clojure code

17:33 blake_: A big difference from OO to FP is that FP doesn't require as much encapsulation, since there's a philosophy of avoiding side-effects.

17:33 justin_smith: right

17:33 kavkaz: I've seen in a Clojure book before the author using multimethods and protocols, but I've never touched those two before

17:33 justin_smith: kavkaz: those become more helpful if you are writing a library where you want end users of the lib to provide concrete functionality

17:33 the kind of thing that gets called IOC or DI in OO

17:34 kavkaz: Oh I see. It's like abstract class in Java?

17:35 Protocols that is... sort of?

17:35 justin_smith: kavkaz: protocols are backed by java interfaces

17:35 hlolli: Justin Smith, just curious, are you not also a csound user?

17:35 justin_smith: or well, jvm interfaces, which are what also backs java interfaces

17:35 hlolli: yes I am, I use csound a lot (but not at work)

17:35 kavkaz: I mixed up abstract classess and interfaces

17:35 justin_smith: well, they are very similar in usage, yeah

17:36 multimethods are similar, but they allow more flexibility in dispatch

17:36 and "default implementations" which are similar to abstract class funcitonality in a way

17:37 hlolli: Ok, Im programming alot with csoung API in Clojure. Maybe you can help me with one thing, since I'm trying to live code with csound using clojure. I'm trying to find a way to make add-watch non-destrucitve. There is to say, if I put an errorous function in add-watch function, it will not fail the Agent and stop everything?

17:37 justin_smith: hlolli: so I assume you follow the csound mailing list? I've been active there on and off.

17:37 hlolli: Yes that's where this name rang a bell.

17:37 kavkaz: justin_smith: blake_ Thanks for your helps, I gotta go now

17:37 blake_: kavkaz: NP

17:38 justin_smith: hlolli: have you checked agent-error and set-error-handler!

17:38 blake_: Wow, csound, that takes me back.

17:39 justin_smith: hlolli: there's a few related things all listed together here - http://conj.io/ - if you check the section about agents

17:39 hlolli: nope, will do!

17:39 justin_smith: blake_: csound is still alive

17:39 blake_: Yeah, but it's been years since I played with it.

17:40 justin_smith: blake_: it looks like there may be a new version of cecelia supporting csound again coming out before long

17:41 hlolli: nice, I will check it out. I've made some algorithms for live-coding but Im hoping to use more recursion. I think I also need to read more about multimethods, there is to say, the way a pattern would behave with different instruments. But that is for future task.

17:41 blake_: justin_smith: Neat.

17:41 justin_smith: blake_: also, csound supports live instrument definition, and multi-core

17:42 (or, newer versions do that is)

17:42 blake_: Gonna say, it's come a long way.

17:56 teoma: Where do asynchronous Quil exception messages go in Cider? I don't see them in the REPL or error buffers, but I've confirmed they appear when starting `lein repl' from the shell.

17:56 hlolli: Ok I looked into set-error-handler! and agent-error. Both of those will not prevent an agent failing, only saving last value without error in a failed agent. My failures are coming trough add-watch wathcers. So If there's a way that the watcher would not evaluate an errorous function in the first place, then it would never fail an agent. I'm thing about some catch/throw kind of way, but maybe validators could work too?

17:58 Have you tried teoma, nREPL buffer, if you're using cider-jack-in it should be created in emacs.

17:59 teoma: hlolli: is that *nrepl-messages*? I don't see the error there...

18:00 hlolli: nrepl-server? Do you have that window? Im currently using shell to create lein repl and I use cider-connect so I may be wrong about the buffer name.

18:01 justin_smith: hlolli: what about putting a try/catch on your watching function?

18:01 err, inside

18:02 teoma: hlolli: *nrepl-messages* seems to be the only buffer with nrepl in its name.

18:02 hlolli: weird, are you using cider-jack-in?

18:03 teoma: hlolli: yes.

18:04 hlolli: Either you must have closed that buffer accedentaly, can try closing cider and restart it. Or there's some cider setting you have that prevents nrepl-server from being generated. Assuming you are using the moser recent version of cider and cider-nrepl.

18:05 (dont know what happens when pasing code to irc)

18:05 (defn event-register [instr p-name matrix pattern]

18:05 ;[instr p-name & {:keys [on-tikk]}]

18:05 (add-watch x-agent (keyword (apply str (name p-name) "-play"))

18:05 (fn [k r old-state new-state]

18:05 (let [on-tikk (event-calculator matrix pattern)

18:05 mod-div (->> (map #(Math/ceil (/ (+ % 0.0001) 256)) on-tikk)

18:06 (apply max)

18:06 (* 256))

18:06 pat-len (count on-tikk)

18:06 t-256 (mod (new-state :t-stack) mod-div)

18:06 ]

18:06 (if (not= (new-state :t-stack) (old-state :t-stack))

18:06 (if (some #(= t-256 %) (map double on-tikk))

18:06 (do (eval instr)

18:06

18:06 (prn (mod (new-state :t-stack) 256))

18:06 ;(prn instr on-tikk "?") ;(prn k (new-state :bar) (new-state :section))

18:06 (send (eval (symbol "hlolli.clock" p-name)) (fn [p-map] (assoc p-map :arp-index (mod (inc (p-map :arp-index)) (p-map :arp-len)))))

18:06 )))))))

18:06

18:06 justin_smith: hlolli: please use refheap.com for code samples

18:06 hlolli: ok, sorry wont do that again. But since it's here, can you see a good place to set the watcher, justin?

18:06 ok will do! sorry

18:07 teoma: hlolli: I have Cider 0.9.1. Maybe it's because nrepl-log-messages is nil (the default).

18:08 hlolli: Oh, actually it's not nil, though the default is nil.

18:08 sdegutis: Just stopped by to apologize for my recent behavior. I've been insufferable, arrogant, haughty, boastful, rude, disrespectful, and in general impolite. I'll do my best to not be such an annoyance anymore, and to be much more grateful for all your help. On that note, thanks for all your help everyone.

18:09 nooga: wow

18:09 hlolli: Did you configure ~/.lein/profiles.clj and set cider-nrepl version etc?

18:09 teoma: hlolli: yes, I have :plugins [[cider/cider-nrepl "0.9.1"]] there.

18:10 justin_smith: hlolli: you could surround the let block with a a try/catch that just prints the exception

18:11 hlolli: ok nice thanks Justin, will try that!

18:11 justin_smith: hlolli: also your eval could be a resolve call (and that would be much better)

18:11 err, the one wherey you have (send (eval ...)) that is

18:11 nooga: hlolli: what's that code for?

18:13 hlolli: It's a time-schedule function, takes in numbers that are triggered from 0 to 255 and the iteration speed of the counter that is modulo of 256 is adjusted by beats per minute. A way to quickly create musical timing patters. But this is one way of many possible. With less code I always loose freedome but gain coding speed.

18:15 nooga: hlolli: overtone huh?

18:15 hlolli: ok, will try resolve call. But this part of the function is just to update pattern info, so it iterates note index so I can make arpeggio patterns or scale patterns.

18:15 justin_smith: nooga: not overtone, overtone has at-at which is much simpler than this

18:15 in fact, you might find it helpful to look at at-at for a good example of scheduling recurring timed tasks

18:16 or even use at-at even if not using the rest of overtone :)

18:16 hlolli: I only use overtone for timing, there's to say, I have an impulse coming from overtone, that's all. All else is Csound based.

18:16 nooga: I discovered extempore recently

18:17 it's not clojure but looks interesting, fast enough to perform synthesis on the fly

18:18 hlolli: I tried metro and chnset for csound. But csound events are inaccurate from +/- 100ms while coming from overtone it's +/- 5ms, can't find a way to get this same accuracy from csound. But then again I know supercollider developers have been really progrimming a good accurate clock while csound development has too little been based on live-coding etc.

18:18 well, "synthesis" itn't extempore all sample based?

18:20 justin_smith: hlolli: it supports sample-based dsp, but I don't know if it ships with anything interesting

18:20 surely not as complete a set of ugens as csound or even supercollider would give you

18:22 hlolli: Yes, extempore sounds good, at least from Andrew Soerensen, really liked his performance when I heard him. Also Im trying to hack with extempore since it has really good emacs multiplexer and also emacs-osc to have the letters dance with the beats.

18:22 nooga: hlolli: you can write a function that writes individual audio samples to dsp

18:22 justin_smith: it's like comparing ms paint to blender, because both can do pixels on a screen, and hey, if you implemented a few functions you could probably do what blender does in paint, right?

18:23 blake_: No good. MS is closed source.

18:23 hlolli: yes, I will admit, samples sound much better, but I'm afraid that once I go samples I will get stuck there and learn little new about sound synthesis.

18:23 But I ofcourse use samples alot.

18:23 nooga: http://benswift.me/2012/06/07/dsp-basics-in-extempore/

18:24 justin_smith: blake_: OK tuxpaint and blender :P

18:24 nooga: these are not samples as in prerecorded sound clips

18:24 justin_smith: nooga: right, that shows you how to turn pixels on and off. Now make a convincing texture of hair on a 3d character.

18:25 nooga: well I think it's much more flexible than ugens if you want to write a synthesizer

18:25 justin_smith: nooga: that's right, it's individual DSP samples. It's still very low level and getting from that to what csound or supercollider provides is years of work.

18:25 nooga: or at least experiment with synthesis

18:25 well

18:26 hlolli: nooga, good question. I guess I could find out, I understand the basics of audio-buffers etc. But can't say I could do it now without internet. Audio programming book would be good source for this. But I guess javasound would be the tool to use.

18:26 blake_: Which is cool, man. If that's what you're interested in. I still like to write DBMSes...

18:26 nooga: some day I'll build a modular synth FROM HARDWARE >:D

18:27 justin_smith: hlolli: steven yi (one of the csound devs) has pink, which is a clojure project that does dsp in pure clojure

18:27 hlolli: this might provide exactly what you want - though it is young, and doesn't have a lot - but it has a whole lot more than extempore does

18:27 hlolli: excacly, I've been following up on him alot.

18:28 justin_smith: nooga: I guess my complaint about the audio api that extempore provides is that it doesn't give me much I couldn't do myself in any language that can hook up to OS audio drivers. And if I'm going to be rolling that much on my own, why do I even need their language?

18:29 hlolli: csound is just such a good fully packed tool, and I know csound, so I've been too hesitant of learning pink and/or supercollider. But I did go deep into overtone.

18:30 nooga: justin_smith: don't know, but I'm sure Andrew had a blast writing it

18:34 teoma: I heard a Rich Hickey lecture where he said Overtone's scheduler suffered from problems that core.async could address. Just curious, do you know what he meant?

18:44 hlolli: No, problems I have been having when trying to prorgam schedulers is that when the state: time is on a specific state and should do event on that state, then the time state could live long enough for more than one event to shoot off. But it's not connected to at I think.

18:47 Anyhov, Justin, this worked! The agent does not crash, but the "problem" now is that I need to find a way for clojure to store my function calls, or redesign it, so that it will continue calling the last function call that worked, but it's much better, even if one pattern fails, the other will continue. But for now a major bug has been solved.

18:54 justin_smith: hlolli: I bet you could do something interesting with core.async, and either repeatedly sending events to a channel, or recirculating them as they are handled back to the sending function for them to come again after a delay

18:55 hlolli: what you are doing now reads as a bit clumsy - it is using some very powerful tools that clojure provides where there are more nuanced (and less powerful) tools that could make this simpler

18:57 hlolli: yes, this is very clumsy for sure. Im learning as Im programming. I've been looking into core.async and for sure I will give that a try for learning experience.

18:58 I did try atoms insted of agents and also some schedulers at stackoverflow, but so far using agents and watchers, I've been able to get the most accurate results. Don't know why, but I just experiment with lot of things and choose the best result.

19:01 well, the force behind the clock is overtone, form there I have on-event function handler that send counted ticks from impulse to a numberpile that is stored in agent, from the agent I will control the events. These agents could be dismissed perhaps but I need some way of storing pattern info in a map etc.

19:01 justin_smith: hlolli: the way you are using the agent with watches, you could have a go-loop per instrument, and a pub/sub (a writer to a publishing channel replacing the agent, readers of subscriber channels replacing the watches)

19:03 hlolli: yes defenitely, I'm very new to core.async, but it shouldn't take a long time to switch over. I may need to rewrite the code anyway to make it more clear and easy to read.

19:09 it's 1am in berlin, so I need to hit the bed. Hope to talk later Justin! Gute Nacht.

19:13 amalloy: i should start using that. "sorry guys, it's 1am in berlin. i gotta go"

19:14 gfredericks: ~g2g is <reply> It's 1am in berlin

19:14 clojurebot: Ik begrijp

19:14 gfredericks: ~g2g is <reply> pager just went off

19:14 clojurebot: Alles klar

19:14 gfredericks: ~g2g is <reply> realized haskell is better

19:14 clojurebot: Ack. Ack.

19:15 gfredericks: ~g2g is <reply> personal segfault

19:15 clojurebot: You don't have to tell me twice.

19:16 ferz_: Hello gents, I crash my REPL when I try to bind input to symbol like so (def data (slurp *in*))

19:16 sdegutis: When running some clojure.test tests via CIDER, and you get an error, is there a way to show what line triggered the error?

19:16 gfredericks: ferz_: shouldn't (slurp *in*) hang?

19:16 sdegutis: All it tells me is the name of the exception (NullPointerException).

19:16 ferz_: Am I doing something wrong? I am able to get initial input but then it crashes with an exception after I run more commands

19:16 gfredericks: sdegutis: I'd check *e in the repl

19:16 sdegutis: gfredericks: oh cool never knew about *e thanks.

19:17 gfredericks: np

19:17 ferz_: gfredericks: I think it does but I ended my input with ctrl-d , whats the standard way to get input and bind it to a symbol

19:18 gfredericks: ferz_: depends how much you want

19:18 sdegutis: Is a lexer or parser a good use-case for using transducers?

19:18 ferz_: gfredericks: so I have to manually specify something?

19:18 sdegutis: It seems kind of like it's right up its alley, but I can't be sure.

19:23 ferz_: I have 4 lines coming in from user input, how do I capture them / bind every word to one long vector for reuse?

19:24 sdegutis: ferz_: It's not clear what you're asking, what the context is.

19:24 ferz_: sdegutis: that's the context hackerrank.com/challenges/diagonal-difference

19:28 sdegutis: Okay.

19:30 ferz_: So whats the standard way to capture the input in a variable.

19:31 sdegutis: ferz_: Probably just read *in*.

19:31 ferz_: (slurp *in*) I'm guessing.

19:31 ,(slurp *in*)

19:31 clojurebot: ""

19:32 sdegutis: That should do it I bet.

19:33 ferz_: right except this is what I get http://pastebin.com/UFm0SV3L

19:34 sdegutis: ferz_: It probably won't work inside a REPL due to the nature of a REPL hijacking *in* for your convenience.

19:34 ferz_: test it using normal standard-input procedures in a terminal.

19:34 ferz_: oh so it's the REPL issue then? Technically it's not my code per se?

19:36 I know there is a (flush) function so I was thinking maybe I am forgetting it or something.

19:38 amalloy: if you slurp *in* you close *in* afterwards, and then the repl can't read new commands from you

19:38 you can just slurp (string-reader "1 2 3 4") instead, and then later replace that with *in* when you're running for real

19:39 ferz_: hm, I'll try that

19:39 sdegutis: ferz_: basically, write your code to take an input, and in the real code use *in*, and while testing use (string-reader "1 2 3 4\n")

19:40 ferz_: a normal function parameter will suffice for this

19:40 ferz_: I'll try that, thanks

19:43 I know I probably sound retarded but I am new to Clojure and trying to learn it by solving some challenges online but they are very specific in their input and etc. it gets confusing with Clojure.

19:48 neoncontrails: ferz_: have a look around. There's lots of challenge sites, and I think they each attract a certain demographic

19:49 My personal favorite is Project Euler. It's not Clojure specific, but you'll learn a lot implementing 10 solutions or so

19:50 ferz_: I did some Euler before, it's pretty math heavy unfortunately

19:52 neoncontrails: There's usually a mathematical interpretation to those problems that can help you avoid brute-force labor, that's true

19:53 TEttinger: my favorite clojure problem is "make it short enough to do something unusual but also fit in one IRC message"

19:54 neoncontrails: I'm not sure that they're really "math problems," in the sense that what they really require is a bit of sophistication and cleverness with how you approach large numbers and number sequences that will blow your stack if you're not careful

19:54 TEttinger: I think of euler as math-heavy personally

19:54 ferz_: yeah thats heavy CS/Math lol

19:55 TEttinger: I never got past pre-calculus in college

19:55 ferz_: I tapped out at Calc 2 so I haven't studied anything beyond that

19:56 neoncontrails: Boo calculus. Hooray linear algebra

19:56 (I never truly fancied math until LinAlg)

19:56 ferz_: See, I didn't even get to that

19:56 I am sure I wouldn't mind other mathematics but Cal 2 (integration) got me good..

19:57 I did well in Trig, Geometry, Algebra

19:57 neoncontrails: Consider taking it if you like computers. You'll find it a lot more relatable than calculus, certainly

19:57 ferz_: I wouldn't be able to that's the thing.

19:57 I had to switch majors eventually

19:58 neoncontrails: Don't be so hard on yourself! Linear algebra doesn't necessarily depend on calculus. At some schools it's not even a prerequisite

19:59 ferz_: I might watch online lectures, that's about it

20:00 neoncontrails: @ferz_: You might enjoy this essay. Strang's terrific -- and his lectures are online, free! http://www-math.mit.edu/~gs/papers/essay.pdf

20:00 ferz_: it is a pre-req in my uni lol

20:00 I am mostly disillusioned by college anyway

20:01 had a teacher for "C programming" who didn't know about K&R.

20:07 neoncontrails: Can someone show me how to format this code to take an operator as input and apply it to the expression? http://pastebin.com/BzV4LA7Y

20:08 This works for adding x and y, but I had to manually write in the +. (apply (:val @op) [x y)) doesn't work here

20:09 Pretend I closed that vector

20:10 justin_smith: neoncontrails: you'd need [(:val @x) (:val @y)]

20:10 neoncontrails: Oh, right. Good call

20:11 justin_smith: ,(do (def op (atom +)) (def x (atom 12)) (def y (atom 30)))

20:11 clojurebot: #'sandbox/y

20:12 justin_smith: ,(apply @op [@x @y])

20:12 clojurebot: 42

20:12 neoncontrails: Outstanding!

20:12 amalloy: (quote + arg) seems super wrong

20:13 justin_smith: neoncontrails: of course you would also need to do the :val dereference for your version

20:13 amalloy: ,(quote + arg)

20:13 clojurebot: +

20:13 justin_smith: neoncontrails: though fyi you can put things other than hash-maps in atoms

20:13 (as above of course)

20:14 neoncontrails: justin_smith: Can you explain briefly what (do ...) is doing here?

20:14 justin_smith: ,(quote x y z a b c d e f g wat)

20:14 clojurebot: x

20:15 justin_smith: neoncontrails: it lets me make less screen scroll by putting three defs in one clojurebot command

20:15 neoncontrails: Haha, bravo. So it's not strictly necessary

20:16 justin_smith: ,(quote x (System/exit 0) (println "WAT"))

20:16 clojurebot: x

20:24 neoncontrails: justin_smith: Just to clarify your example and amalloy's, what's the issue with the way I used quote?

20:25 I recognize that it's not correct, but I'm not sure I understand why

20:27 amalloy: quote receives a single expression, and protects that expression from evaluation: in (let [x 1] [x, (quote x)]), x evaluates to 1, but (quote x) evaluates to x

20:27 giving quote more than one expression just makes no sense

20:28 hiredman: http://dev.clojure.org/jira/browse/CLJ-1282

20:28 the comments on that issue

20:28 neoncontrails: I see. I was hoping the quote might be a wrapper I could use to safely pass operators around without evaluating them

20:29 But that was just a hope

20:56 mdeboard: thanks to amalloy and justin_smith I am now poised to reap sweet, sweet StackOverflow points http://stackoverflow.com/questions/23600387/how-do-you-write-to-a-log-file-in-clojure-using-core-async/32491340#32491340

20:56 Look at me, I am the expert now

20:58 dbasch: mdeboard: that’s good, because when Stack Exchange goes public they’ll issue shares to users proportionally to their karma points

20:58 mdeboard: Sweeeeeeeeet!

20:58 I have a whole 430

20:59 dbasch: mdeboard: I just made that up of course

20:59 mdeboard: That puts me in 95th percentile I'm sure

20:59 dbasch, Too late, you said it, You're liable

21:00 dbasch: having one upvoted answer probably puts you in the 95th percentile

21:00 mdeboard: (I do not give a rip about SO karma etc., I was being cheeky :))

21:01 (I also do not actually know how SO works)

21:06 amalloy: mdeboard: you are actually in the top 4% of SO users

21:07 diminishedprime: If I'm writing a macro and want to name an argument "name" as in [name & rest], is there a way to do that without running into issues from clojure.core/name ?

21:07 mdeboard: wat.

21:07 I guess the bar is pretty low.

21:07 amalloy: yes, it is

21:07 mdeboard: and the user base is high

21:07 i.e. huffing spray paint

21:07 amalloy: or wait maybe i am doing bad math?

21:07 mdeboard: diminishedprime, I'd say don't call it 'name' or any other .. name that stomps stdlib functions.

21:08 -name, name- are easy alternatives

21:08 thing-name, etc., etc.

21:08 amalloy: http://stackoverflow.com/users/495154/mattdeboard claims top 68%, but http://stackexchange.com/leagues/1/alltime/stackoverflow/2008-07-31/495154#495154 makes it look like your rank is pretty high

21:08 mdeboard: ...leagues?

21:08 welp

21:08 amalloy: oh, that's all of stackexchange

21:08 mdeboard: *deletes account*

21:10 diminishedprime: mdeboard: I suppose that'd be the best solution. Is there a generally accepted practice for naming when you want to name something that's already in the stdlib?

21:10 mdeboard: I.E. -name- vs name-

21:11 amalloy: it is good fun to call it name, and then later try to call clojure.core/name

21:11 i don't know why you would want to rob yourself of that adventure

21:11 mdeboard: diminishedprime, I sure don't know. Local (to your codebase) consistency is more important than a language-wide stylebook (unless we're talking about Python)

21:12 Just generally you should avoid stomping built-ins :)

21:13 diminishedprime: mdeboard: Yeah, that makes sense. I didn't really think of what the overall effect would be to override "name" (or for that matter if it's even possible), but I see that if anything else in that namespace was using the stdlib name, then there'd be some serious issues.

21:15 mdeboard: well it would only matter inside that function body of course

21:16 diminishedprime: mdeboard: Yeah, but that body is potentially quite large, the macro system would be used for a dsl for some business folk.

21:16 mdeboard: i see

21:19 diminishedprime: mdeboard: Thanks a lot!

21:20 mdeboard: you're welcome

21:40 chomwitt: contrary to some tutorials i've read in the lein repl i can use (fully qualified) symbols from other ns , like clojure.string or ns defined by me. How can i check which namespaces have been required(loaded) in the current ns?

21:40 amalloy: chomwitt: namespace loading is global. if someone else loads a namespace, the stuff in it comes into existence and anyone can use it

21:41 but you generally should specifically require anything you need, so that you don't rely on "oh this other file is loading the namespace i need" and then that stops working when namespace load order changes or whatever

21:44 chomwitt: amalloy: the strange to me is that none introductory material i've read is clear (to me at least) on this topic.

21:44 for example first time i learn that namespace loading is global (what ever that means exactly, cause i'm newbie in clojure) :-)

21:46 i've have an ebook in front of me now that says that in a repl in a ns i must require clojure.set.. but i use it with no require

21:46 justin_smith: chomwitt: well, some code somewhere alreayd required it

21:46 chomwitt: except if that require happens one time per session and i've forgot it

21:47 amalloy: chomwitt: there are a lot of things you "must" do, like look both ways before crossing the street, but there's no law of physics that forces you to

21:47 most of the time, no car hits you

21:47 but it's still something you should do

21:48 chomwitt: justin_smith: should i reboot my pc to reset and test a fresh repl so that nothing would have already 'required clojure.set or whatever?

21:48 amalloy: justin_smith: clojure.core requires clojure.set and clojure.string

21:49 justin_smith: chomwitt: no, that's not really needed

21:49 amalloy: oh, I wasn't aware

21:50 amalloy: in a virgin java -jar repl, clojure.set/union gives me a ClassNotFoundException for clojure.set

21:50 :P

21:50 I wouldn't be surprised that every other lib ever written uses both those though

21:51 chomwitt: so maybe 'lein repl' does some things differently..

21:51 TEttinger: I rarely use clojure.set for some reason

21:51 justin_smith: oh, it definitely does

21:51 emdashcomma: Yesterday I was facing an awkward REPL situation

21:51 I put the code at the end of Ch. 4 of Brave Clojure in a file and then opened a REPL -- I got a lot of runtime exceptions

21:51 chomwitt: justin_smith: was that line related to my last one?

21:52 emdashcomma: I then typed all of it into a REPL outside of that project, and it worked fine -- what's going on?

21:52 justin_smith: chomwitt: yes - lein repl uses nrepl, that loads a bunch of things that are not present in a "vanilla" clojure.jar repl

21:52 chomwitt: justin_smith: thanks

21:52 justin_smith: emdashcomma: which functions were causing the errors

21:53 emdashcomma: Let me get the exact line

21:54 chomwitt: i think i'd help me to have a command like 'ns-map' to check the status of loaded (required?) ns in my current one. now i probe with TAB to see what's loaded.

21:55 emdashcomma: > Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: create in this context

21:55 'create' is nowhere in the code, though

21:55 justin_smith: chomwitt: all-ns

21:55 amalloy: justin_smith: what about clojure.string?

21:56 justin_smith: amalloy: that one is loaded

21:56 amalloy: probably clojure.repl loads string then, not clojure.core

21:57 justin_smith: amalloy: nope, clojure.repl is loaded here https://www.refheap.com/109368

21:57 chomwitt: justin_smith: thanks again .

21:58 justin_smith: chomwitt: here is a fun one: (into {} (map ns-publics (all-ns)))

21:58 amalloy: right, i said string, not set. i wasn't disagreeing with you

21:59 i was clearly wrong about clojure.set, and also concluding that it's probably not clojure.core that loads clojure.string, but clojure.repl

21:59 alif-baa: emdashcomma: and what code were you running

22:00 chomwitt: justin_smith: thats a lot output do digest !

22:01 emdashcomma: http://pastebin.com/PtFpNvrj

22:03 justin_smith: chomwitt: see also clojure.repl/apropos

22:03 ,(clojure.repl/apropos "namespace")

22:03 clojurebot: (clojure.core/namespace clojure.core/namespace-munge)

22:04 justin_smith: ,(clojure.repl/apropos-doc "namespace")

22:04 clojurebot: #error {\n :cause "No such var: clojure.repl/apropos-doc"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.RuntimeException: No such var: clojure.repl/apropos-doc, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyze "Compiler.java" 6704]}\n {:type java.lang.RuntimeException\n :message "No such var: clojure.repl/apropos-doc"\n :at [clojure.lan...

22:04 justin_smith: ,(clojure.repl/apropos "apropos")

22:04 clojurebot: (clojure.repl/apropos)

22:04 justin_smith: hmm, must be an extension I forget where from

22:08 ,(clojure.repl/find-doc "namespace")

22:08 clojurebot: -------------------------\nclojure.core/*data-readers*\n Map from reader tag symbols to data reader Vars.\n\n When Clojure starts, it searches for files named 'data_readers.clj'\n at the root of the classpath. Each such file must contain a literal\n map of symbols, like this:\n\n {foo/bar my.project.foo/bar\n foo/baz my.project/baz}\n\n The first symbol in each pair is a tag that w...

22:08 justin_smith: that's the one, repl/find-doc, searches for a string and regex in clojure doc strings

Logging service provided by n01se.net