#clojure log - May 25 2015

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

0:23 bluesnow: What is a tuple in Clojure? My book Programming Clojure mentions "tuples" but they don't seem to be an actual data structure type

0:47 loke: bluesnow: a "tyuple" normally is a fixed set of values

0:47 I mean tuple

0:48 bluesnow: ah I see. okay, thanks.

0:48 amalloy: well, a fixed-size collection

0:48 loke: You might want to read this, if you want to gritty details: https://en.wikipedia.org/wiki/Tuple

0:50 bluesnow: loke: cool. I'll take a look at that page.

0:56 jtmarmon: is there a way to do an "unquote"/"unquote-splicing" within a regular quoted statement instead of within a backtick? if not, why not?

0:59 bbloom: ~backtick

0:59 clojurebot: Cool story bro.

0:59 bbloom: jtmarmon: no, but:

1:00 https://github.com/brandonbloom/backtick

1:00 you can use the "template" function

1:00 although the use cases are pretty esoteric

1:00 template *macro* i mean

1:01 jtmarmon: duude nice

1:01 (inc bbloom)

1:01 lazybot: ⇒ 55

1:01 jtmarmon: also I've noticed the clojure community really likes the word complect

1:02 bbloom: turns out to be a useful word :-P

1:02 jtmarmon: if datomic sells to fb rich hickey will buy a league of legends team and name it complecsity

1:02 (http://lol.gamepedia.com/CompLexity_Gaming)

1:03 bbloom: none of those things seem likely.

1:04 jtmarmon: fyi @bbloom - use case is for datomic queries. I have a bunch of optional boolean flags to pass as inputs to the query

1:04 bbloom: huh?

1:04 somebody can probably suggest a more straightforward approach if you gist some code

1:05 jtmarmon: ok so example:

1:07 dating site where you can filter by food preference. i want suiters to be able to only look at potential suitors who like pizza. so the datomic statement might be [?person :person/likesPizza true] but only if that flag is there. otherwise no filtering

1:07 lol i used suitors twice and once incorrectly. (inc 2am)

1:07 bbloom: can't you just concatenate some clauses?

1:08 jtmarmon: oh

1:08 yeah

1:08 bbloom: start with some base query and conj on additional clauses

1:08 jtmarmon: how do oyu do that clojurebot thing again

1:08 bbloom: (let [query ..., query (if (some? pizza) (conj query '[?person :person/likesPizza true) query), ....

1:09 (let [query ..., query (if (some? pizza) (conj query '[?person :person/likesPizza true]) query), .... ; add missing ]

1:09 jtmarmon: okay yeah you're totally right

1:09 bbloom: that's kinda half the damn point for the design of datomic's query syntax :-)

1:09 jtmarmon: i just didn't consider that because it's quoted. still working on getting into the whole "nothing is special (usually)" style of programming

1:10 bbloom: also, rather than making one attribute per food, you should use just make :person/likes a cardinality many attribute

1:10 jtmarmon: yeah bad example. i swear i'm not starting a food related dating site

1:10 although not a bad idea...

1:11 bbloom: (reduce (fn [query thing] (conj query ['?person :person/likes thing])) initial-query likes)

1:11 tada: tag filters!

1:11 doesn't get simpler than that

1:11 jtmarmon: dang

1:11 that's perty

1:12 man i actually went to sql from mongodb and i really hated dealing with strings so it's nice to be back :D

1:12 er sorry, mongodb -> sql

1:12 bbloom: mongo's queries have atrocious composition properties

1:12 i mean, better than sql strings, but still pretty awful

1:13 jtmarmon: yeah well they try to stuff everything into objects. it's all...complected...

1:13 e.g. {thing: {$qualifier: and {thing: {field

1:14 bbloom: it's certainly complicated, but you can't say complected unless you specify which two or more things are complected together :-)

1:15 but yes, the distinction between lists and vectors is very useful for separating meta syntax from more general use of sequences

1:15 bluesnow: What does something like (:customer %) or (:total %2) mean in Clojure?

1:16 bbloom: bluesnow: https://yobriefca.se/blog/2014/05/19/the-weird-and-wonderful-characters-of-clojure/

1:16 also http://clojure.org/reader

1:19 bluesnow: bbloom: ok, thanks for the references

1:54 Okay, I have a question about something in my clojure book. It does (def flat-breakup {["Wile Coyote" "Anvil"] 900, ["Elmer Fudd" "Anvil"] 300})

1:54 Then it does (reduce #(apply assoc-in %1 %2) {} flat-breakup)

1:54 It says that this will result in assoc-in being called thus - (assoc-in {} ["Wile Coyote" "Anvil"] 900)

1:55 I'm wondering why the above happens instead of (assoc-in {} [["Wile Coyote" "Anvil"] 900])

1:55 Why are the [k v] for a map entry being separated out into k v when assoc-in is called?

2:10 noidi: bluesnow, it's the apply

2:11 (apply f [a b c]) = (apply f a b c)

2:11 sorry

2:11 (apply f [a b c]) = (f a b c)

2:16 bluesnow: noidi: Ah okay, thanks.

2:22 Also quick question about the documentation for apply

2:23 It says that the arguments for apply could look like [f a b c d & args]

2:23 What does the & symbol mean?

2:23 (It says that the options for calling apply are [f args], [f x args], [f x y args], [f a b c d & args]

2:24 I'm not sure how the & symbol makes the last option different from [f x y args]

2:34 noidi: the & symbol means that the function can take extra arguments in addition to the required ones named before the &

2:35 the sequence of extra arguments is assigned the name after the & (in this case "args")

2:35 ,((fn [x y & args] [x y args]) 'a 'b 'c 'd 'e 'f)

2:35 clojurebot: [a b (c d e f)]

2:36 bluesnow: noidi: Uh hmm. Okay, I'm not sure I see why this is a separate option in the case of apply

2:37 I thought apply took [f x y z .. (as many single args as desired) args (where args is a vector of args)]

2:38 Empperi: apply takes a list of arguments

2:38 ,(doc apply)

2:38 clojurebot: "([f args] [f x args] [f x y args] [f x y z args] [f a b c d ...]); Applies fn f to the argument list formed by prepending intervening arguments to args."

2:39 Empperi: there is only a limited amount of function declarations for apply where it takes arguments all by themselves

2:39 the last one is a vararg version, which works nice due to that

2:40 bluesnow: Empperi: Still confused unfortunately. In the first option, [f args], isn't args a vector?

2:41 Empperi: yes, let me give you an example

2:41 ,(apply + [1 2 3])

2:41 clojurebot: 6

2:42 Empperi: ,(apply + 1 [1 2 3])

2:42 clojurebot: 7

2:42 Empperi: ,(apply + 1 2 [1 2 3])

2:42 clojurebot: 9

2:42 Empperi: and so forth

2:42 bluesnow: right

2:42 I understand that

2:42 Empperi: the way apply works is that the last argument has to always be a seq

2:42 bluesnow: yeah

2:42 Empperi: and that's what it's documentation says: "Applies fn f to the argument list formed by prepending intervening arguments to args."

2:42 bluesnow: right, I understand that part of the doc

2:43 Empperi: ok, so your confusion was about?

2:43 bluesnow: Wait so is [f a b c d & args] saying that we can have as many single args as we want, and then we can put all the rest of the args into the vector?

2:44 I was confused about what the & in [f a b c d & args] meant

2:45 So the & in [f a b c d & args] says that we can put as many remaning arguments into the vector args as we want?

2:46 Empperi: it means there can be any number of intervening arguments before the last argument which has to be a seq

2:46 bluesnow: oh okay, that makes sense. Someone else explained it differently above.

2:47 Empperi: well, he was right in what he said

2:47 but that's how apply works under the hood

2:47 the way & works is that it means "0-n arguments in here"

2:48 bluesnow: right

2:48 Empperi: apply just digs the last argument out of that, uses that as a seq and ensures that all the intervening arguments are prepended to that seq

2:49 if you look at the source code of apply you see what I mean

2:49 https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L623

2:49 bluesnow: Yeah, the part he said that confused me was "the sequence of extra arguments is assigned the name after the & (in this case "args")"

2:49 Empperi: notice the call to "spread"

2:49 yeah, well he was right :)

2:49 bluesnow: I didn't see why the sequence of arguments would be assigned the name "args"

2:49 Empperi: but it's just the starting point for the internal logic of apply

2:50 it's because it's named as 'args'

2:50 see the source code

2:53 bluesnow: Empperi: Oh I see. I'm pretty new to Clojure, but from what I can tell, the rest of the arguments after a b c d are added by spread to the args vector

2:53 I'm having trouble reading some of this code. Just started learning Clojure

2:53 Empperi: no problem dude, happy to help :)

2:54 the way apply works and why it exists in core, is that it allows you to call functions dynamically with variable amount of arguments

2:54 if you didn't have apply you'd have to always know the amount of arguments when calling your function

2:55 which would force you to require people to pass in seqs

2:55 so apply is very often used with functions which have variable arguments

2:55 + is a great example

2:55 ,(+ 1 2 3 4 5)

2:55 clojurebot: 15

2:55 Empperi: works

2:55 but so does this

2:55 ,(apply + [1 2 3 4 5])

2:55 clojurebot: 15

2:55 Empperi: and this

2:56 ,(apply + (range 1 6))

2:56 clojurebot: 15

2:56 bluesnow: Empperi: Right. I have one more question about something in the docs. The docs say that the argument list for assoc-in is ([m [k & ks] v])

2:56 Empperi: you'd have to have a separate version of + which would accept seqs or add additional logic into it which would check if the argument is a seq to make that last example work

2:56 without apply

2:56 bluesnow: where ks is a sequence of keys

2:57 Empperi: yeah, lol. assoc-in is a confusing one

2:57 update-in is even more so lol

2:57 but yeah, assoc-in uses a lisp functionality called destructuring in it's function declaration

2:57 assoc-in is called like this:

2:58 bluesnow: so based on that doc, I thought that when I did (assoc-in {} [:a :b (seq [:c :d])] 5) I would get {a: {b: {c: {d: 5}}}}

2:58 Empperi: ,(assoc-in {} [:foo :bar] 1)

2:58 clojurebot: {:foo {:bar 1}}

2:58 bluesnow: right

2:58 Empperi: what it does is that it'll receive the second argument and destructures that

2:58 by the destructuring rules, which in this case is [k & ks]

2:58 bluesnow: Empperi: But based on the docs, I thought it could be (assoc-in {} [:foo :bar (seq [:foo_again :bar_again])] val)

2:59 Empperi: you're confusing this with apply

2:59 apply works exactly the same but with the difference it does it's own magic inside the function

2:59 bluesnow: yeah, the way the docs are written, is [k & ks] supposed to be a vector?

2:59 Empperi: when your call to apply is done, it's exactly the same in the beginning

2:59 it can be any seq

2:59 bluesnow: right

3:00 Empperi: (assoc-in {} '(:a :b) 1)

3:00 ,(assoc-in {} '(:a :b) 1)

3:00 clojurebot: {:a {:b 1}}

3:00 bluesnow: but based on the docs, it seems like ks could be another seq nested inside that seq

3:00 since the docs say it's [k & ks], so it looks like a variable number of individual keys followed by another nested sequence ks

3:00 Empperi: not really, nesting is something actually why assoc-in exists :)

3:00 you have assoc for non-nested cases

3:00 ,(assoc {} :foo 1)

3:00 clojurebot: {:foo 1}

3:01 bluesnow: hmm okay. I'm just trying to figure out why the docs are written that way so I can read the docs correctly

3:01 Empperi: I think you should read about clojure destructuring

3:01 bluesnow: Why do they write it as [k & ks] if they don't mean that the ks can be a nested seq?

3:01 Empperi: it is it's own little mini language

3:01 bluesnow: Empperi: I've read a bit about clojure destructuring

3:02 Empperi: [k & ks] means, you'll have to provide at least one key but you can provide as many as you wish

3:02 [& ks] would mean 0-n

3:02 bluesnow: right

3:02 But why not write it as [k & last_key], to make it clear that the last argument should be an individual key, not a nested seq?

3:03 They say that "ks" is a sequence of keys, so that seems like it would be a seq nested inside the first seq

3:03 Empperi: well, ks/last_key can contain multiple keys

3:03 so 'last-key' would be a bit misleading, don't you think?

3:03 bluesnow: Why would it be misleading? since we have the & in between k and last_key, then it seems clear that we could have 1-n keys

3:03 Empperi: but you don't see the & inside the function

3:04 not unless you look at the function parameter declaration

3:04 eg. (doseq [k last-key] (println k)) would look totally wierd naming wise

3:04 weird

3:05 bluesnow: Empperi: Oh hmm, ok. I think it might look weird to me since I'm only looking at the docs

3:05 Empperi: it's one of the naming conventions in clojure which is all over the place

3:05 bluesnow: Ie, I'm entirely reading the docs without looking at the source code, which might be why the docs seem written in an odd way

3:05 okay, sounds good

3:05 Empperi: you usually don't have to look at the source code

3:06 I like to read them though to give me a better understanding of how stuff works under the hood

3:06 bluesnow: Empperi: Right, got it. So, if the doc writers had actually meant for ks to be a nested seq inside the first seq, how would they have written that?

3:07 Empperi: yeah, see eg. https://clojuredocs.org/clojure.walk/postwalk

3:07 that function works with nested data structures

3:08 bluesnow: I see

3:09 hmm okay, thanks

3:10 Empperi: np

3:10 happy to help

5:22 justin_smith: it's called ks because & only creates seqs

5:22 [k & [next-key]] would also make sense

5:22 but there is not destructuring that would give you last-key

5:25 currento_:

5:39 Confusion: This seems a bit weird: ArityException: Wrong number of args (-2) passed to: Symbol

5:39 Is this a bug in the error message?

5:39 justin_smith: Confusion: iirc this is a bug in error messages for macros

5:39 ,(or)

5:39 clojurebot: nil

5:39 Confusion: ack

5:39 justin_smith: ,(and)

5:39 clojurebot: true

5:39 justin_smith: hmm

5:40 ,(for [i (range)])

5:40 clojurebot: #error {\n :cause "Wrong number of args (1) passed to: core/for"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (1) passed to: core/for"\n :at [clojure.lang.Compiler macroexpand1 "Compiler.java" 6636]}]\n :trace\n [[clojure.lang.Compiler macroexpand1 "Compiler.java" 6636]\n [clojure.lang.Compiler macroexpand "Compiler.java" 6702]\n [clojure.lang.Compiler eval "...

5:41 justin_smith: ,(#'for [i (range)])

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

5:41 justin_smith: ,(#'for [])

5:41 clojurebot: #error {\n :cause "Wrong number of args (1) passed to: core/for"\n :via\n [{:type clojure.lang.ArityException\n :message "Wrong number of args (1) passed to: core/for"\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" 32]\n [clojure.lang.Var invoke "Var.java" 379]\n [sandbox$eval114 invoke "NO_...

5:41 justin_smith: never mind, I thought I remembered how to make that happen, clearly I don't

5:42 Confusion: If I figure out what causes it without rewriting the lot, I'll let you know :)

6:04 crocket: Clojure, the king.

6:25 ionthas_: is there a elegant way to generate a vector like this? [1 0 1 0 1 0 1]. Right now I'm using loop recur.

6:26 ronh-: ionthas_ take + cycle?

6:26 kaiyin: ,(interpose 0 (repeat 1))

6:26 clojurebot: (1 0 1 0 1 ...)

6:27 kaiyin: ionthas_: ^

6:27 ionthas_: wow, that's a neat way to do it kiyin

6:27 kaiyin, thanks

6:27 ronh-: ,(cycle '(1 0))

6:27 clojurebot: (1 0 1 0 1 ...)

6:28 crocket: ,(doc interpose)

6:28 clojurebot: "([sep] [sep coll]); Returns a lazy seq of the elements of coll separated by sep. Returns a stateful transducer when no collection is provided."

6:28 crocket: (take 5 (interpose 0 (repeat 1)))

6:28 ,(take 5 (interpose 0 (repeat 1)))

6:28 clojurebot: (1 0 1 0 1)

6:33 crocket: Why does (commute) execute once in a transaction and once after the transaction?

6:33 doesn't make sense.

6:40 Ah, I get it

6:57 What does '#' do in #'+?

6:57 Very mysterious.

7:00 TMA: ,#'+

7:01 clojurebot: #'clojure.core/+

7:01 TMA: ,'+

7:01 clojurebot: +

7:01 TMA: ,+

7:01 clojurebot: #object[clojure.core$_PLUS_ 0x55e37a06 "clojure.core$_PLUS_@55e37a06"]

7:14 amalloy: ,(quote #'+)

7:14 clojurebot: (var +)

7:38 Confusion: I have a macro (defmacro run [expr] `(inc ~expr)). This works fine: (run (+ 1 1)) returns 3. But the arguments I actually have are already unevaluated lists. I can't seem to figure out how to make the macro that makes (run (list + 1 1)) return 3. Is this indeed tricky or am I overlooking something simple?

7:39 bendlas: Confusion: that's the reason you let-bind input expressions in a macro, to ensure single-evaluation: (defmacro run [expr] `(let [expr# ~expr] (inc expr#)))

7:40 Confusion: oh sorry, misread the question

7:41 what you want in this case is actually to call eval from the macro

7:41 (defmacro run [expr] `(inc ~(eval expr)))

7:42 just beware, that the expression will be evaluated at compile time

7:42 of course, you could also expand to a call to eval, to evaluate it at run time

7:43 (defmacro run [expr] `(inc (eval ~expr)))

7:43 depending on your needs

7:44 Confusion: bendlas, OK, thanks, it seems there is then no way around eval for my use case.

7:44 wlr: #haskell

7:45 bendlas: Confusion: no, there isn't. The only thing you could do is to implement a subset of eval tailored to your needs.

7:45 but to eval at compile time isn't all that bad

7:46 Confusion: bendlas, true, but it's going to have to be at runtime. Fortunately the input already conforms to an instaparse grammar, so it's probably safe

7:47 bendlas: Confusion: ok, the go-to idiom for runtime eval is (defmacro make-runner [expr] `(fn [] ~expr))

7:48 thus you can still take proper advantage of the JIT and such

7:48 Confusion: Ah, that's interesting!

7:49 bendlas: erm, sorry: (defn make-runner [expr] (eval `(fn [] ~expr)))

9:03 Empperi: fuck yeah, it looks like I'm getting to Euroclojure

9:13 zalatovo: Is there a way to pass the name for a let binding into a macro?

9:13 right now I'm using something like `(let [~var ...] ...)

9:14 bendlas: zalatovo: that's the usual way, what would you like to do that you can't do with that?

9:14 zalatovo: bendlas: it doesn't seem to work, I get a "no such var" RuntimeException

9:15 bendlas: it probably has something to do with namespaces

9:15 I'm trying to write a (with-connection db (open ...) ...body...) macro which automatically closes db

9:16 db is the name that should be bound by the let in the body

9:16 chouser: zalatovo: Have you looked at the source code for the with-open macro?

9:17 zalatovo: chouser: I haven't but I'll take a look

9:17 chouser: Hm, as usual there's a bit more there than you might hope: https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L3677

9:18 zalatovo: the strange thing is that the macro works just fine if I expand it manually and then run it

9:18 chouser: zalatovo: anyway, you may be able to use with-open itself. If not, you must be close.

9:18 zalatovo: chouser: it does look a lot like what I'm trying to do but this is more of a macro exercise for me than something I really need

9:19 bendlas: zalatovo: sounds strange, care to pastebin?

9:19 chouser: zalatovo: sure. Maybe post the whole macro someplace?

9:19 zalatovo: I'll do that

9:20 https://gist.github.com/anonymous/34897ea9039a2bce427d

9:20 think that's all of it

9:21 chouser: ah! what's that 's' about? :-)

9:21 bendlas: chouser yep

9:22 zalatovo: chouser: what do you mean?

9:22 bendlas: line 8

9:22 zalatovo: ahhh I see it now haha

9:22 rookie mistake

9:22 chouser: :-)

9:22 zalatovo: thanks for the help anyway

9:24 chouser: so, the clue in the error message is the fully-qualified symbol. Your message was something like "No such var: test-project.foo/s" right?

9:24 zalatovo: yep

9:25 chouser: But your 's' was never meant to be a "var" but rather a local

9:26 zalatovo: I'm not entirely sure of the difference

9:26 chouser: So that suggests that something was fully-qualifying 's' when you didn't want it to. And syntax-quote (that is, the backtick `) fully-qualifies any symbol it can't resolve.

9:26 zalatovo: locals are bound by let whereas a Var is created using def?

9:27 bendlas: zalatovo: that's the primary difference

9:27 chouser: zalatovo: essentially, yes. Vars made via def live in a namespace and have a full name, like test-project.foo/with-string-stream

9:27 (there are also anonymous vars but seriously nobody uses those)

9:28 zalatovo: (let [x 10] test-project.foo/x) here the x would refer to a var instead of the local x?

9:28 bendlas: vars can also be thread-local (via ^:dynamic and binding), can hold macros, compiler macros

9:28 yes

9:28 zalatovo: that makes sense

9:31 chouser: Whoa, I take it back. People use with-local-vars to an insane degree! https://github.com/search?l=clojure&q=with-local-vars&ref=searchresults&type=Code

9:31 bendlas: also, not to forget, vars are mutable (volatile), contrary to immutable let bindings

9:32 zalatovo: aha

9:32 also during macro expansion do symbols like print get resolved to clojure.core/print etc?

9:32 chouser: ...though mutating even vars much is not encouraged.

9:32 zalatovo: that's what I understand from the reader docs

9:33 chouser: zalatovo: not during macro expansion, but during syntax-quote reading

9:33 zalatovo: aha

9:33 chouser: , `(list foo)

9:33 clojurebot: (clojure.core/list sandbox/foo)

9:34 chouser: no macros expanded there, but syntax-quote read each symbol as fully-qualified.

9:34 'list' was resolved to the real var clojure.core/list, whereas 'foo' wasn't found as a var anywhere, so the current namespace (sandbox) was assumed

9:35 bendlas: chouser: that step has always been kind of lost to me (if not explicit by `). It must also implicit as the first step to eval, right?

9:36 chouser: bendlas: right, syntax-quote resolves vars during read, but eval also resolves vars if necessary.

9:37 bendlas: so, the analyzer resolves them in the namespace context, if not in the lexical context ...

9:37 zalatovo: so something like (let [var 'foo] `(list ~var)) causes syntax-quote to use the fully qualified name for list and simply splice in the foo symbol without resolving it

9:38 noncom: is anyone here familiar with lein uberjar and handling of native libraries ?

9:38 chouser: zalatovo: exactly!

9:38 I think this is a difference between Clojure's sorta-hygenic syntax quote compared to Common Lisp's not-at-all-hygenic backquote

9:38 zalatovo: chouser: then I understand why I got that particular error message :0

9:39 chouser: zalatovo: excellent!

9:40 bendlas: yep, if I understand you.

9:40 noncom: *shudder* a bit

9:42 bendlas: Actual analyzer actually analyzing a symbol: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L6906

9:42 noncom: chouser: umm, i'm having a very strange problem. i include lwjgl libraries in my project.clj. and then in my source, I call "(org.lwjgl.opengl.Display/setLocation screen-x screen-y)"

9:43 chouser: that works ok from the IDE (Eclipse + CCW), but fails with no class found exception in jar made by lein uberjar. it cannot find the Display class

9:43 TMA: ,(let [var 'foo] `(list ~var '~var ~'var ~'foo 'foo))

9:43 clojurebot: (clojure.core/list foo (quote foo) var foo ...)

9:44 chouser: bendlas: so: local, unqualified class name, qualified static Java field, var, actual class object, and finally "unresolved"

9:44 bendlas: chouser: right, even #'foo gets passed to the analyzer as (var foo)

9:44 chouser: ,(read-string "#'foo")

9:44 clojurebot: (var foo)

9:45 noncom: chouser: what's more strange, the app that itself uses opengl starts fine if i just remove the call

9:45 chouser: bendlas: yep.

9:46 noncom: hm. It's complaining about not finding the Java class? nothing about a native lib or an unresolved function?

9:46 noncom: chouser: yes. the fact is that the class is there in the jar. my guess about the natives trouble is that it cannot load the class because it cannot load the natives that it requires

9:47 bendlas: noncom: are the natives (*.so) in the jar?

9:47 noncom: chouser: what is really odd, the app *is* starting ok with all that stuff, and the app internally uses that very opengl...

9:48 bendlas: uberjar is not great at reproducing behavior of the regular packaging, in corner cases

9:48 noncom: bendlas: awit, checking for the *.so files... why isn't it so great? does not it fullfill its duty?

9:49 bendlas: i'd say it does, as good as can be done for the general case. but there is just to much weirdness in the combination of java's classpath and maven

9:50 * bendlas tries to remember a specific case that came up

9:51 bendlas: e.g. when having duplicate files on your class path, uberjar can include a different one than you would get for a regular run (even though duplicate files on CP might be called undefined behavior)

9:51 noncom: bendlas: well, i am on windows and those are dll files and yes, they're there in the jar

9:52 bendlas: strange thing is - the application *does* create the display and run inside it...

9:52 chouser: native libs don't follow the same classloader and classpath rules that class files do.

9:52 noncom: you're not getting any other errors or warnings before the class-not-found error?

9:52 noncom: let me check again...

9:54 bendlas: IIRC, .so files (or dll files, if you will), need to be unpacked to a temp dir, before being loaded by the JVM, though I don't know what code does that

9:55 chouser: I think that's right, and it's up to each Java lib to do that itself.

9:57 bendlas: noncom: also double check, if you don't have that issue with duplicate files on your class path. if your .class files get switched to a version that doesn't fit with its .so, it might just result in a class not found error

10:00 noncom: well, it gives this, actually: http://joxi.ru/5mdkdLzuQw6Pr1

10:00 sorry, that's a bit different error

10:03 chouser: ah, yeah, that's a native lib error.

10:03 noncom: damn.. it worked a week ago

10:03 chouser: so java.library.path is usually set at jvm startup (though I'm sure IDEs will mess around with it)

10:04 anyway, the .dll (or .so) needs to be in one of the directories listed in java.library.path

10:04 profil: Empperi: through opportunity grant or what? :)

10:04 noncom: somehow, everything just works in Eclipse. when i try to publicsh a clojrue app, i usually get a bunch of errors... i am so tired of being bound to eclipse for clojure apps to just work...

10:05 chouser: There may be some Java code in jgl or Eclipse somewhere to unpack the .dll from some .jar file and put it in some java.library.path directory

10:06 I have some vague recollection of lein also having such code. Hm...

10:06 noncom: actually, there was time, i had to write such a plugin for lein by myself: https://bitbucket.org/noncom/nativot

10:07 but i avoid using it if i can..

10:07 chouser: https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L290

10:07 noncom: chouser: that's for compile-timne i think

10:08 my problem is that the already compiled jar does not start ok

10:08 chouser: oh! You may be right.

10:11 Empperi: profil: my company sends me there

10:13 noncom: chouser: why can't they just make it so that the tool just works as it should...

10:13 bendlas: noncom: I don't know what eclipse's equinox does automagically, but why not use something along the lines of https://github.com/scijava/native-lib-loader

10:14 also, relevant SO: http://stackoverflow.com/questions/2937406/how-to-bundle-a-native-library-and-a-jni-library-inside-a-jar

10:16 noncom: bendlas: wow, thank you for the links!

10:16 now i just have to tie it together with leiningen..

10:18 bendlas: noncom: yw, let us know how it went :-)

10:19 noncom: haha, if i get some result.. :) i am so blind tired of all this things, including classloading... you know, since i am creating a software for internal use, i just ship it with Eclipse...

10:19 that's a shame, but i spent literary days on figuring similar kind of problems and solutions for them with clojure...

10:21 bendlas: like, this one my message: https://groups.google.com/forum/#!topic/clojure/dY4AmXCDnxw none of the official did not even say a thing. only 2 ppl proposed some complex workarounds.. and just 1 irrelevant question "what version of clojure are you using" from someone, who's expected to really answer the question...

10:21 sad, that's just sad..

10:28 bendlas: noncom: well, there is always a bit of luck involved, in your message getting read by a person who is able to help along. all in all, I think most members of the community share your disgust in java's classloading model

10:32 also, for me, the chance of fully comprehending a message on the mailing list and thus being able to match it with my own experience, increases exponentially with every minute effort to strip it down to it minimized form (in terms of introduced concept, not nessecarily words)

10:36 jtmarmon: is there a simple way to do a conditional kv within an object? I usually do (merge (if thing {:t thing} {}) {:rest :of :object :here}) but is there a way I can just do {:rest :of :object :here (some-magical-splicing-conditional)}

10:39 bendlas: jtmarmon: such splicing is only available at read time, via the new reader conditionals

10:39 chouser: (conj {:rest :here} (when thing [:t thing]))

10:39 (-> {:rest :here} (cond-> thing (assoc :t thing)))

10:40 bendlas: ^ this

10:40 jtmarmon: ah great, thank you!

10:41 chouser: or with synthread: (-> {:rest :here} (->/if thing (assoc :t thing)))

10:42 profil: Empperi: oh, you lucky. Are you working with clojure?

10:57 noncom: bendlas: yeah, i know.. but what can i do.. if the topic is like that :)

11:00 bendlas: noncom: keep focussing on the core of the problem, until you have a kernel that's almost trivial to convey.

11:01 then you only need to convince people that it is actually the root of something relevant ;-)

11:02 noncom: :) well, maybe i made my google groups quesion explanation too broad... indeed, it could be fit within 1-2 lines of text maybe..

11:03 bendlas: I think clojure, in the large, sets a great precedence of building something more simple on top of something as baroquely complex as the jvm. which is in equal parts miraculous when viewed from the OOP side, as well as easy to underestimate when used to it

11:06 ... but i guess that goes for every useful abstraction

11:08 ... and same as most useful abstractions, it has its corner cases where leaks spring as soon as you put the pressure on

11:23 stain: hi, is it possible to do some magic to add Clojure methods to an existing Java class or interface? E.g. make a third-party org.apache.commons.Foo also be Seqable and IPersistentMap?

11:23 or should I better make a bunch of wrappers

11:24 which then have to wrap their constituent fields etc

11:26 chouser: stain: alas, no such magic. If Seqable and IPersistentMap were protocols (like they are in ClojureScript), you could use extend-type. But alas they are Java interfaces, so you have only the normal Java options.

11:27 So, yes, wrappers.

11:28 stain: or, if you don't really need Clojure's existing interfaces to work, you can make your own protocols or multimethods and extend them to 3rd party classes as well as Clojure's own.

11:28 stain: yeah, that might be easier

11:32 I'm thinking of the best way to make a Clojure bridge for the Commons RDF API (Java interfaces) http://commonsrdf.incubator.apache.org/apidocs/org/apache/commons/rdf/api/package-summary.html - which naively and natively could just be like this in clojure: https://github.com/stain/commons-rdf-clj/blob/master/src/commons_rdf_clj/graph.clj

11:33 but my problem is I have not decided which direction I would want to bridge.. :)

11:36 rpaulo: ]]]]]]]]]]]]]]]]]]]]]]]]]]

11:36 oops, cat

12:15 studentrob: Hi, I'm new to Clojure. I have a function that, given two arguments, returns a number. I want to make a priority-map using the second argument as the key and the returned result as the value ... http://pastebin.com/zrtNVkyt

12:17 This is part of a kata, and I probably haven't read as much of "Clojure Programming" as I should have so far

12:19 _1_Melvin2: hello

12:21 chouser: studentrob: clojure doesn't come with a priority-map. There is a sorted map, but beware your comparison fn must describe a full stable order (no returning of 0 unless the two keys are *actually* equal)

12:31 studentrob: Hi Chouser, thanks for your reply. (Had to look it up online in the logs as I was disconnected.) .... I'm using an external library for priority map which I guess makes this hard for other people to run, doh.. I'll try sorted-map

12:32 I have the same issue with sorted-map .... I'm not sure how to set up the map function properly to get key-value pairs .... I can make a vector of keys, and a vector of values separately but am not sure how to match them up

12:33 maybe rather than using map I should loop

12:42 justin_smith: studentrob: any reasonable hash-map implementation should give you a sequence of entries if you call map on it

12:42 ,(map identity {:a 0 :b 1 :c 2 :d 3})

12:42 clojurebot: ([:a 0] [:b 1] [:c 2] [:d 3])

12:53 studentrob: Thanks Justin . I figured it out via a loop. My problem was constructing the "innards", :a 0 :b 1 :c 2 :d 3 , properly .. I ended up with this : http://pastebin.com/9dtPYpr7 .. If that can be accomplished using the map function, I'd love to know how, but it was beyond my brain capacity as I've just started learning this language

12:54 justin_smith: studentrob: that's not a map, that's a reduce

12:55 and it's reducing on cand, not the priority-map

12:55 the priority-map is the accumulator for reduce

12:55 studentrob: okay, cool, I haven't read about reduce yet

12:55 I'll take note of your comments and read up on that

12:56 justin_smith: (reduce (fn [pm w1] (assoc p1 w1 (dist w1 goal))) (priority-map) (filter #(= (count %) (count goal)) words))

12:56 that should work in the place of your loop ^

12:56 cap10morgan: Is there a simple rule for when to use put! vs. >!! in core.async?

12:59 justin_smith: cap10morgan: does the next line of code break if the value was not consumed yet?

12:59 if yes, use >!!, if no, use put!

12:59 cap10morgan: ah, b/c >!! blocks but put! does not?

12:59 justin_smith: right

13:00 cap10morgan: justin_smith: OK, thanks. that makes sense.

13:04 studentrob: Thanks, I understand reduce now!

13:04 justin_smith: studentrob: awesome, it's a very useful and flexible function

13:04 studentrob: once I figured out reduce, I realized it could replace almost every usage of loop I had been using

13:05 jtmarmon: ok im very confused - is there something that can make a function exit early in clojure other than an exception? for some reason this function exits early and i can't figure out why. https://gist.github.com/jtmarmon/9e7491b8ebcff3d4d8f6

13:05 studentrob: Yeah. Seems like a very common operation, pretty handy

13:07 justin_smith: jtmarmon: I can't reproduce

13:07 jtmarmon: so weird o_O

13:07 justin_smith: jtmarmon: if I call (wtf {:a 0}) I see both "hi1" and "hi2"

13:08 jtmarmon: are you giving postwalk something that's lazily generated and potentially infinite?

13:09 jtmarmon: it's a datomic entity map...maybe?

13:18 justin_smith: ok converting the entity map to a hash-map and calling wtf still prints "hi1" only

13:18 wat

13:20 it must be something with the runtime. i'm running this via "lein ring server". it works fine in my repl, just not in the server logs

13:25 i'm so confused T_T

13:27 justin_smith: jtmarmon: one thing I like to use is a: make sure I have a repl in the ring process (starting the server from a repl, or running clojure.tools.nrepl will work) then using an atom to store the args to the problematic function

13:27 which lets me come back and interactively use the data, and figure out what went wrong

13:27 it's one of the nice side effects of using immutable data

13:28 jtmarmon: very helpful, thanks. i'll see if i can figure it out that way

13:28 justin_smith: eg. (defonce debug (atom [])) and then inside your function arg (swap! debug conj problem-input)

13:28 *inside your function

13:42 gfredericks: I like the quick-and-dirty method of just throwing a (def arg arg) inside a function

13:42 justin_smith: haha, there's that too

13:43 gfredericks: although this makes me want to write some utils for my . namespace that can as-easily-as-possible start capturing args & return values

13:43 justin_smith: like a tools.trace that stores the values and lets you look them up

13:43 bonus if it also stores timestamps so you can go find the arg that was supplied an hour ago etc.

13:44 jtmarmon: so it seems i'm getting an abstractmethoderror on the "conj" step of postwalk but it's not being thrown for some reason... https://gist.github.com/jtmarmon/9e3e6826460b51b8f616

13:45 nor do i know why it's happening in the first place

13:45 gfredericks: justin_smith: well there's lots of leak issues there

13:45 justin_smith: oh, yeah, it's by definition a huge space leak

13:46 gfredericks: jtmarmon: how do you find out about it if it doesn't get thrown?

13:46 jtmarmon: i stored it in an atom and re-called the function myself

13:46 justin_smith: jtmarmon: my guess is that into is trying to populate the empty version of some data structure from datomic, and it's failing

13:46 because that data structure is weird or something I guess?

13:46 jtmarmon: oh wtf it works now

13:46 -_-

13:46 justin_smith: haha

13:47 jtmarmon: not the whole thing, just when i call it manually

13:54 okay, so if i select certain keys from the object it works fine...meaning there's just some k-v pairs in the map angering rich

13:56 gfredericks: ,(defrecord Foo [a b])

13:56 clojurebot: sandbox.Foo

13:56 gfredericks: ,(select-keys (->Foo 1 2) [:a :c])

13:56 clojurebot: {:a 1}

13:56 gfredericks: ,(type (select-keys (->Foo 1 2) [:a :c]))

13:56 clojurebot: clojure.lang.PersistentArrayMap

13:57 gfredericks: jtmarmon: select-keys can take a special kind of map and turn it into a generic map

13:57 puredanger: Are you missing the id?

13:57 gfredericks: ,(type (select-keys (sorted-map :a 3) [:a :c]))

13:57 clojurebot: clojure.lang.PersistentArrayMap

13:58 jtmarmon: puredanger: what do you mean?

13:58 puredanger: Never mind, didn't read enough of the back chat

14:00 jtmarmon: gfredericks: into {} converts the datomic result into a persistenthashmap. how can I get it to use a persistentarraymap instead

14:00 gfredericks: jtmarmon: normally those two are functionally equivalent; I'd expect them to be w.r.t. clojure.walk at least

14:01 ,(type (into {} {:hey :ya}))

14:01 clojurebot: clojure.lang.PersistentArrayMap

14:01 jtmarmon: o_O wat

14:01 oh i see

14:01 gfredericks: jtmarmon: looks like it uses an arraymap for small maps probably

14:03 jtmarmon: so to recap i'm threading the datomic result set through (map #(into {})) and then through (postwalk #(if (keyword? %) (keyword (name %)) %)). if I comment out postwalk, I get a response. if I don't comment it out, i get nothing

14:03 gfredericks: what does "get nothing" mean?

14:04 is this a ring server?

14:05 jtmarmon: yes

14:05 yeah okay, exception is being eaten i'm sure of it

14:05 gfredericks: it's probably worth putting some effort into figuring out how to get exception details with your setup

14:05 what's the http response exactly? 500 with empty body?

14:06 this is probably the most appropriate thing: https://ring-clojure.github.io/ring/ring.middleware.stacktrace.html

14:06 Seylerius: What's the best way to push something through a stack of functions that alternately need it at the start and finish?

14:07 Really, it's one that needs it at the start, and the rest can use it at the finish, actually...

14:07 gfredericks: I'm having trouble parsing that

14:07 Seylerius: I figured it out.

14:08 gfredericks: that was easy

14:08 Seylerius: Yep

14:08 SagiCZ: hey guys.. i am trying to get some information from a server using SOAP request.. the response is this https://www.refheap.com/101650 .. it should contain a xml file with the configuration but all i see is some huge random string.. how would i obtain the xml?

14:08 gfredericks: glad I could help

14:08 Seylerius: gfredericks: Basically, I need to use ->>. The first function takes the value at the start, but the rest are all mapv

14:08 SagiCZ: im very new to SOAP

14:09 Seylerius: So, something like (->> (select board :foo) (mapv func))

14:09 With as many mapvs as I'm going to need.

14:09 board is the value pushed in.

14:10 gfredericks: Seylerius: a bunch of mapvs can be squashed into one

14:11 SagiCZ: looks like it's base64 with some more xml in it

14:11 justin_smith: transduce that junk yo!

14:11 SagiCZ: gfredericks: base64 is some kind of hashing? bear with me i am a total noob.. it is supposed to contain xml indeed

14:12 justin_smith: SagiCZ: base64 is a safe way to encode arbitrary data in a subset of ascii

14:12 Seylerius: gfredericks: Actually, this is where I'll need to talk with y'all. I need to nest deeper with each pass. Basically, I've got a GUI structure that contains text boxes nested 3 layers in, and I need to preserve the shape while extracting the data.

14:12 justin_smith: so it's used for things like email attachments

14:12 Seylerius: sounds like a job for postwalk

14:13 gfredericks: Seylerius: you might want to show some examples

14:13 SagiCZ: gfredericks, justin_smith thank you both guys.. it really is just encoded.. very simple but i didnt know what to google so you saved me!

14:13 Seylerius: So board is a grid-panel containing 9 grid-panels, containing 9 grid-panels, containing 9 text boxes.

14:13 arav93: clojure.xml/parse expects a URI as input

14:13 Seylerius: Each grid-panel needs to turn into a vector, and the text boxes need to be numbers.

14:14 arav93: BUt it seems to show an exception when I pass one

14:15 Seylerius: (This makes my brain feel like a matryoshka doll)

14:17 gfredericks: Seylerius: yeah clojure.walk sounds plausible

14:17 Seylerius: gfredericks: prewalk might be better than postwalk, because they won't really become seqs until processed.

14:18 gfredericks: yeah

14:18 justin_smith: Seylerius: the generic "walk" that does both might be an option here

14:18 Seylerius: I suppose the function would just have to detect whether it got fed a grid-panel or a textbox, and then do the Right Thing™ from there

14:18 gfredericks: ,(clojure.walk/prewalk #(repeat (rand-int 3) %) 42)

14:18 justin_smith: yeah, that's what walking code usually looks like

14:18 clojurebot: #error {\n :cause "clojure.walk"\n :via\n [{:type java.lang.ClassNotFoundException\n :message "clojure.walk"\n :at [java.net.URLClassLoader$1 run "URLClassLoader.java" 366]}]\n :trace\n [[java.net.URLClassLoader$1 run "URLClassLoader.java" 366]\n [java.net.URLClassLoader$1 run "URLClassLoader.java" 355]\n [java.security.AccessController doPrivileged "AccessController.java" -2]\n [java.net.U...

14:19 gfredericks: ,(require 'clojure.walk)

14:19 clojurebot: nil

14:19 gfredericks: ,(clojure.walk/prewalk #(repeat (rand-int 3) %) 42)

14:19 clojurebot: ((() (((((()) (() (((# #)))))) (() (() (((() (#))))))))) ())

14:19 gfredericks: ^ protip

14:19 justin_smith: haha

14:19 Seylerius: Heh.

14:19 gfredericks: I wonder how to measure the expected size based on the arg to rand-int

14:20 it reminds me of random-walks and trying to describe the probability that a walk returns to the origin

14:20 justin_smith: gfredericks: it would be an unbounded lazy seq no matter what, wouldn't it?

14:20 arav93: could someone show an example where clojure.xml/parse works?

14:20 :/

14:20 gfredericks: ,(clojure.walk/prewalk #(repeat (rand-int 3) %) 42)

14:20 clojurebot: ((((()) ((((() ()))) (()))) (((() (()))))))

14:21 gfredericks: justin_smith: ^ no

14:21 justin_smith: gfredericks: ahh

14:21 arav93: I don't seem to get it to work

14:21 justin_smith: gfredericks: but in the pathological case it could hypothetically be unlimited

14:22 gfredericks: justin_smith: right -- but there's a specific probability of it being unlimited

14:22 something in the range [0,1)

14:22 justin_smith: ahh, so expected size isn't a number, it's more of a curve

14:22 gfredericks: I assume it's positive for large enough n but don't know for sure

14:23 justin_smith: well expected size is infinity if there's a positive probability of infinite size

14:23 could be infinity even without that

14:24 jtmarmon: ahah http://comments.gmane.org/gmane.comp.db.datomic.user/4773

14:24 justin_smith: jtmarmon: there you have it

14:25 jtmarmon: any idea what "clojure data" entails here? i'm already mapping it to a hash-map which i thought would be enough

14:25 justin_smith: jtmarmon: at every level?

14:25 jtmarmon: ah i suppose not

14:25 justin_smith: it could have been a nested data issue

14:33 jtmarmon: justin_smith: any idea what i'm missing here? error is still hanging around https://gist.github.com/jtmarmon/229e07936d19f53d7d60

14:34 arav93: So, I tried this '(clojure.xm/parse "http://www.cnn.com")

14:35 I got "SAXParseException The entity name must immediately follow the '&' in the entity reference. com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException (ErrorHandlerWrapper.java:198)"

14:50 Seylerius: When prewalk descends, does it descend into the transformed result, or the original?

14:51 ie, can prewalk work with a function that turns non-seqs into seqs, and descend into those?

15:00 andyf: Seylerius: I am pretty sure the whole distinction between pre walk and post walk is whether the supplied function is applied before descending deeper (pre walk) or after returning from descending (post walk). Have you tried pre walk on a toy example?

15:01 Gue______: Seylerius: > (clojure.walk/prewalk #(if (= 1 %) [0 0] %) [1 0 1 0 1])

15:01 [[0 0] 0 [0 0] 0 [0 0]]

15:01 > (clojure.walk/prewalk #(if (= 1 %) [0 1 0] %) [1 0 1 0 1])

15:01 java.lang.StackOverflowError

15:02 Seylerius: andyf: nah, postwalk starts at the bottom and works up.

15:02 Look at prewalk-demo and postwalk-demo

15:03 But looking closer at postwalk reveals that prewalk (if it behaves like postwalk in all respects except going top-down) will operate on the result of the function.

15:04 andyf: Seylerius: To get to the bottom, post walk must start at the top :)

15:05 Seylerius: andyf: Look at the demo functions.

15:05 crash_ep: Seylerius: not sure if my paste went through…

15:05 > (clojure.walk/prewalk #(if (= 1 %) [0 0] %) [1 0 1 0 1])

15:05 [[0 0] 0 [0 0] 0 [0 0]]

15:05 > (clojure.walk/prewalk #(if (= 1 %) [0 1 0] %) [1 0 1 0 1])

15:05 java.lang.StackOverflowError

15:06 andyf: I did. They show when the supplied functions are applied. They don't show how post walk gets to the bottom in the first place.

15:06 crash_ep: shows that the walk does descend into the value returned from the function if it returns a seq.

15:06 Seylerius: crash_ep: Ah.

15:08 crash_ep: Yeah, that proves it.

15:08 prewalk is what I need.

15:08 Thanks.

15:08 crash_ep: np

15:08 Seylerius: (inc crash_ep)

15:08 lazybot: ⇒ 1

15:25 Seylerius: There a function to tell if a vector contains vectors or just numbers?

15:27 'Cause I need to build a walk function that prewalk can call that will simply return the argument if there are more vectors, and do shit if the argument only contains numbers

15:27 Actually, wait, I can skip that step.

15:28 bendlas: ,(every? number? [1 2 3 4])

15:28 clojurebot: true

15:28 bendlas: ,(every? number? [1 2 [3 4] 5])

15:28 clojurebot: false

15:30 mmeix: I'm trying to write a cond-clause which evaluates to true if and only if the number 1 appears only once in a coll ... I have now: (= 1 (count (filter #{1} c)))

15:30 Could this be done simpler?

15:32 bendlas: ,(some #{1} [1 2 3 4])

15:32 clojurebot: 1

15:32 bendlas: ,(some #{1} [2 3 4])

15:32 clojurebot: nil

15:32 ToxicFrog: bendlas: "appears only once" is the key.

15:32 It should pass for [1 2 3 4] but fail for [1 1 1 1].

15:33 mmeix: exactly

15:33 bendlas: OIC, in that case, no

15:33 ToxicFrog: mmeix: that said, #{1} can probably be replaced with (partial = 1). Not sure if that's clearer to you, though.

15:33 mmeix: clearer - yes

15:34 ToxicFrog: Oh hey

15:34 Seylerius: Making an int from a string?

15:34 ToxicFrog: I think you want frequencies

15:34 Seylerius: Just int?

15:34 mmeix: ah!

15:34 frquencies I forgot about

15:34 ToxicFrog: ,(-> [1 2 3 4] frequencies 1 (= 1))

15:34 clojurebot: #error {\n :cause "java.lang.Long cannot be cast to clojure.lang.IFn"\n :via\n [{:type java.lang.ClassCastException\n :message "java.lang.Long cannot be cast to clojure.lang.IFn"\n :at [sandbox$eval121 invoke "NO_SOURCE_FILE" 0]}]\n :trace\n [[sandbox$eval121 invoke "NO_SOURCE_FILE" 0]\n [clojure.lang.Compiler eval "Compiler.java" 6792]\n [clojure.lang.Compiler eval "Compiler.java" 6755]\n ...

15:34 ToxicFrog: right whoops

15:35 ,(-> [1 2 3 4] frequencies (get 1) (= 1))

15:35 clojurebot: true

15:35 ToxicFrog: ,(-> [1 2 3 4 1] frequencies (get 1) (= 1))

15:35 clojurebot: false

15:35 bendlas: only, frequencies does more work, which might or might not be relevant

15:35 Seylerius: ,(int "4")

15:35 clojurebot: #error {\n :cause "java.lang.String cannot be cast to java.lang.Character"\n :via\n [{:type java.lang.ClassCastException\n :message "java.lang.String cannot be cast to java.lang.Character"\n :at [clojure.lang.RT intCast "RT.java" 1163]}]\n :trace\n [[clojure.lang.RT intCast "RT.java" 1163]\n [sandbox$eval193 invoke "NO_SOURCE_FILE" 0]\n [clojure.lang.Compiler eval "Compiler.java" 6792]\n [c...

15:36 bendlas: ,(Long/valueOf "4")

15:36 clojurebot: 4

15:37 mmeix: in this case performance might matter, because this is in the dispatch function of a multimethod

15:38 I'm dealing with an awful collection of rules to solve a graphic problem (music setting), and just trying to tame the beast with intelligent dispatch

15:42 the frequencies-method seems to run about 10 times longer, trying with (time ...)

15:42 ,(time (-> [1 2 3 4 1] frequencies (get 1) (= 1)))

15:43 clojurebot: "Elapsed time: 0.538152 msecs"\nfalse

15:43 mmeix: ,(time (= 1 (count (filter #{1} [1 2 3 4 1]))))

15:43 clojurebot: "Elapsed time: 0.12773 msecs"\nfalse

15:43 Deraen: count will have to realize the whole filter, you could use first and second instead of it:

15:43 ,(time (let [x (filter #{1} [1 1 2 3 4])] (and (first x) (not (second x)))))

15:43 clojurebot: "Elapsed time: 0.223119 msecs"\nfalse

15:44 mmeix: if that matters: count is seldom more than 20 in my case

15:44 Deraen: Though that will only matter with collections larger than seq chunk-size or something

15:44 mmeix: understood

15:45 so filtering and counting in such small vectors is not that bad

15:52 a strategic question as follow- up: is a lookup of ready-made solutions in form of a map a feasable way, timingwise? I have to deal with a domain with a lot of small special rules, so in some cases the needed calculations for a single case are a lot. I thought about creating a map with, say 30-50 of the most frequent cases, and using the functional machinery only for the few remaining ... not a pure solution, but maybe practical.

15:57 TEttinger: mmeix: most efficient would probably be an array with the indices exactly as you want them

15:57 assuming you are giving and returning primitives

15:58 mmeix: my input would be something like [0 1 0], and it's solution [1 0 -1]

15:58 a vector of offsets to add to the input

15:59 TEttinger: so... your numbers are always 1, 0, or -1?

15:59 mmeix: no

15:59 TEttinger: or are there a lot of possible entries?

16:00 mmeix: [0 0 1], [0 1 1], [0 1 2], [0 2 2], [0 2 3], etc, up to 7 for each place

16:00 TEttinger: friggin' sweet. I get to use bit twiddling

16:01 mmeix: oh ...

16:01 TEttinger: depends how crazy you need speed

16:01 mmeix: it's clojurescript project, music notation in a browser

16:02 TEttinger: oh then none of my advice applies

16:02 mmeix: I'm not sure about needed speed yet

16:02 TEttinger: arrays make the most sense for JVM opts, probably don't exist in JS (they're not like Java arrays, at least)

16:03 mmeix: so maybe simple maps might be the way to go

16:03 TEttinger: yes

16:03 mmeix: it's about untangling the many possible cases

16:03 into simple lookup

16:03 TEttinger: JS objects are pretty much everywhere in JS code, so I'd bet they are optimized by JS engines extremely heavily

16:03 mmeix: I thought this might be just simpler

16:04 TEttinger: objects should be best

16:04 mmeix: ok, something to think about - great & thanks!

16:06 TEttinger: where an object corresponds to a map, I mean, mmeix

16:07 they are probably extremely similar at runtime

16:07 mmeix: in JS every object is similar to a clojure(script) map, I think

16:08 will think & try

16:09 thanks! & bye ...

17:30 turtil: Aside from the Changelog, is there anywhere I can find a list of substantial changes from Clojure 1.4 to the Current Release? Basically im re-reading Clojure Programming (O'Reilly) and Programming Clojure (Prag Bookshelf) and im wondering how current these books will be for the most part

17:36 bbloom: turtil: clojure is very stable & backwards compatible. you'll miss out on some new stuff, but nothing you learn will be wrong

17:36 the only stuff that i can think of that's meaningfully deprecated occurred before clojure 1.4, so don't worry about it

17:37 kaiyin: Can I set *out* to something similar to /dev/null on unix machines?

17:39 andyf: kaiyin: I'm not aware of anything specific for that in Clojure. Here is a StackOverflow question for Java: http://stackoverflow.com/questions/691813/is-there-a-null-outputstream-in-java

17:39 kaiyin: I'd recommend trying (clojure.java.io/writer "/dev/null") on a unix-like machine and see if it works as expected, but that would probably not be portable to non-unixes.

17:40 bbloom: ,(clojure.java.io/writer "/dev/null")

17:40 clojurebot: #error {\n :cause "denied"\n :via\n [{:type java.lang.SecurityException\n :message "denied"\n :at [clojurebot.sandbox$enable_security_manager$fn__881 invoke "sandbox.clj" 69]}]\n :trace\n [[clojurebot.sandbox$enable_security_manager$fn__881 invoke "sandbox.clj" 69]\n [clojurebot.sandbox.proxy$java.lang.SecurityManager$Door$f500ea40 checkWrite nil -1]\n [java.io.FileOutputStream <init> "FileO...

17:40 bbloom: aw

17:40 kaiyin: ok

17:40 andyf: bbloom: Can't have people breaking security by making the bots discard data :)

18:05 turtil: bbloom: thanks for that, i will continue as per normal then :)

18:36 TimMc: file:///dev/null I think

18:37 bbloom: ,(clojure.java.io/writer "file:///dev/null")

18:37 clojurebot: #error {\n :cause "denied"\n :via\n [{:type java.lang.SecurityException\n :message "denied"\n :at [clojurebot.sandbox$enable_security_manager$fn__881 invoke "sandbox.clj" 69]}]\n :trace\n [[clojurebot.sandbox$enable_security_manager$fn__881 invoke "sandbox.clj" 69]\n [clojurebot.sandbox.proxy$java.lang.SecurityManager$Door$f500ea40 checkWrite nil -1]\n [java.io.FileOutputStream <init> "FileO...

18:37 TimMc: but really you'd just want to make an OutputStream that threw away all writes

18:39 The second answer on that SO link is good.

18:51 arohner: what's the name of that clojure.test replacement library that has almost the same API?

18:53 bbloom: .... if it has almost the same api, what's the point?

19:06 auxchar: Anyone know a good example project for clj-ssh?

19:24 turbofail: auxchar: pallet, presumably

19:42 auxchar: Thanks, turbofail.

20:10 elvis4526: Is there a way to combine multiple regexp together in a single pattern ?

20:11 Is there a way to combine multiple regexp together in a single regexp?

20:11 I tried with (re-pattern) but its annoying to be forced to escape each backslash you enter

20:18 Shayanjm: is there a structural difference between conventional 'arrays' in other languages and vectors in clojure? Or is it just semantics?

20:19 andyf: elvis4526: Should be able to write a function that combines multiple together, with some assumptions or limitations of what each regex contains.

20:19 elvis4526: Nothing existing in Clojure's library, but someone has probably written something for themselves.

20:19 Shayanjm: Arrays in most languages are mutable, and O(1) access time to any element.

20:20 Shayanjm: andyf: do clojure vectors not have O(1) access time to elements?

20:20 andyf: Shayanjm: Clojure vectors are immutable, and to get immutability the best known implementation require O(log n) access time and update time, with memory allocation required for each update. The base of the log is 32 in the implementation, which helps keep # of memory references low.

20:20 Shayanjm: ahhhh

20:20 thanks andyf

20:20 much appreciated

20:21 andyf: There are blog posts explaining the details of how the implementation works, but I don't have a link ready and waiting for it.

20:22 Shayanjm: Most notably, Clojure's immutable vectors are *not* binary trees, which in practice are quite a bit slower than 32-way branching trees for reads.

20:22 Shayanjm: gotcha

21:17 arohner: bbloom: re: clojure.test earlier. it cleans up a few things regarding e.g. fixtures

21:18 I implemented basically the same thing in Circle's codebase, but I monkeypatched clojure.test directly

21:20 iirc, in raw clojure.test, calling a test fn directly doesn't call its fixture

21:24 gfredericks: arohner: sounds right

21:24 arohner: gfredericks: do you remember the name of the clojure.test replacement library? almost exactly the same API

21:24 gfredericks: arohner: do you think there's an obviously correct behavior for calling a test directly w.r.t. :once fixtures?

21:24 arohner: no

21:25 arohner: I don't think there's an obviously correct way w/ :once fixtures, and I don't use them

21:25 IMO, they're a sign your tests are too stateful

21:25 implicit global state ,etc etc

21:34 gfredericks: arohner: that's an interesting point

21:34 arohner: gfredericks: I'm a full-blown convert to stuartsierra/component. It cleaned up my tests a lot

21:39 gfredericks: arohner: yeah I definitely use it; I should check what my :once fixtures were about

21:40 justin_smith: ugh, I feel so lazy. I was going to make all the tests on my cljc port of component pass this weekend

21:40 instead I took naps

21:40 andyf: justin_smith: Forgive yourself

21:41 justin_smith: I'll have to :)

21:41 gfredericks: arohner: looks like the only one was for resetting the database

21:41 justin_smith: I still want to make those tests pass though, maybe I'll do it on the clock

21:41 gfredericks: I had a couple others but they were fast enough that they could be switched to :each with no noticeable slowdown

21:41 arohner: gfredericks: why not reset before every test?

21:41 TEttinger: gfredericks, I watched part of that random talk, been meaning to watch the rest

21:42 gfredericks: arohner: I think I had something else for that, that made it not as slow

21:42 TEttinger: it's making me wonder about clojure's language-level rand-int and rand-nth but no srand

21:42 gfredericks: arohner: I can't remember it's kind of complicated :/

21:43 TEttinger: yeah I think that's somewhat of an orthogonal problem

21:43 unless you wanted to get ambitious and make it splittable while you were at it

21:43 TEttinger: heh

21:43 gfredericks: TEttinger: but I have a ticket for that

21:43 TEttinger: nice

21:43 gfredericks: TEttinger: http://dev.clojure.org/jira/browse/CLJ-1452

21:44 TEttinger: I've been wondering about language-level state, function-level state, etc.

21:45 gfredericks: yeah when I started developing that talk I was at least going to mention that clojure's builtin rng api is about the least useful possible

21:45 but that turned out to not really fit

21:46 TEttinger: like, would it be good to be able to set fields in a function. (set rand .state 12345)

21:47 (this is for my language, which is clojure-inspired but not really a lisp)

21:48 gfredericks: TEttinger: I think clojure-style is to use dynamic vars for this kind of situation

21:49 which is strictly more useful than C's global srand

21:49 clojure < C < clojure+*rand*

21:50 I suppose you could argue that srand in C being global means you just shouldn't use it at all and therefore it's not more useful than clojure

21:50 dunno

21:51 TEttinger: also, what do you think about the claims made by PCG-random ?

21:51 $google pcg random

21:51 lazybot: [PCG, A Family of Better Random Number Generators | PCG, A ...] http://www.pcg-random.org/

21:52 gfredericks: I'm not the best for comparing algorithms

21:52 I've read through that page a couple times and I don't think they're aiming for a general splittable RNG

21:53 unless "multiple streams" means something different than what it sounds like

21:54 TEttinger: http://www.pcg-random.org/useful-features.html#id3

21:54 apparently it is splittable

21:57 gfredericks: TEttinger: what part of that page suggests that?

21:59 TEttinger: I may misunderstand the splittable part. the same seed can be used to construct 2^63 different RNGs, since it uses 63 bits to determine how it permutes the LCG generator result

21:59 gfredericks: 2^63 isn't enough :)

22:00 TEttinger: how many is enough?

22:01 ,(Math/expt 2 63)

22:01 gfredericks: well that was misleading

22:01 clojurebot: #error {\n :cause "No matching method: expt"\n :via\n [{:type clojure.lang.Compiler$CompilerException\n :message "java.lang.IllegalArgumentException: No matching method: expt, compiling:(NO_SOURCE_PATH:0:0)"\n :at [clojure.lang.Compiler analyzeSeq "Compiler.java" 6740]}\n {:type java.lang.IllegalArgumentException\n :message "No matching method: expt"\n :at [clojure.lang.Compiler$StaticMet...

22:01 TEttinger: ,(Math/pow 2 63)

22:01 clojurebot: 9.223372036854776E18

22:01 gfredericks: it's more that that kind of algo structure doesn't really lend itself to splittability

22:01 TEttinger: ah

22:01 gfredericks: in a general splittable RNG you don't know a priori how many rngs you'll need to split into

22:02 TEttinger: but you will encounter a limit at some point

22:02 gfredericks: so the API for a splittable rng is more or less:

22:03 (create seed) => rng; (rand-long rng) => long; (split rng) => [rng rng]

22:03 how would you implement such an api on top of the PCG generator?

22:04 in particular what do create and split do w.r.t. those 2^63 possible ways to initialize the PCG?

22:04 the difficulty is not knowing what is the structure of splitting the user will perform

22:25 danielcompton: ping cfleming

22:26 cfleming: danielcompton: pong

22:26 danielcompton: I've started getting super weird cljsbuild error messages from a Cursive REPL that I don't get from a Lein REPL, does that ring any bells?

22:27 cfleming: danielcompton: There is a cljsbuild bug that affects Cursive because Cursive uses trampoline - one sec

22:28 danielcompton: https://github.com/cursiveclojure/cursive/issues/369 and https://github.com/cursiveclojure/cursive/issues/386

22:28 danielcompton: Does that look like your issue?

22:29 danielcompton: cfleming: yep thats it. I'm a bit puzzled though because it's only just started showing up for me...

22:29 cfleming: danielcompton: Dunno - it's an upstream cljsbuild bug

22:29 danielcompton: No-one ever got to the bottom of it, and Chas closed it as "no patch provided"

22:30 danielcompton: https://github.com/emezeske/lein-cljsbuild/issues/204

22:30 danielcompton: If you feel like debugging and fixing it, many people including me will be very happy :-)

22:31 danielcompton: cfleming: I have enough trouble keeping my cljs projects building successfully, but maybe if I get frustrated enough I'll dig in

22:31 cfleming: danielcompton: How much value is cljsbuild actually providing you with recent versions of cljs?

22:32 danielcompton: It seems like cljs itself handles most of the building itself these days

22:32 danielcompton: cfleming: I've really been enjoying dnolen's mies templates with just scripts, but I wanted something to give me an autoloading clojure frontend and backend for a quick project so chestnut was *was* a good option

22:35 cfleming: danielcompton: Here's a description of how to get figwheel working with just scripts - this is thanks to jackjames, I haven't had a chance to write it up properly yet. https://www.refheap.com/101322

22:35 danielcompton: cfleming: ta

22:35 cfleming: danielcompton: That gives you figwheel + REPL.

22:35 danielcompton: cfleming: now I want to get to the bottom of it just for the glory

22:36 cfleming: danielcompton: I like a masochist

22:48 Does anyone have any experiences to report using cloverage? Does it work well?

22:49 danielcompton: cfleming: yep

22:49 cfleming: well

22:49 cfleming: it needs to be interpreted in my experience.

22:49 cfleming: danielcompton: Nice, thanks. No problems with subtle differences after the code instrumentation?

22:50 danielcompton: cfleming: what do you mean about differences?

22:50 cfleming: danielcompton: You mean the output needs to be interpreted?

22:50 danielcompton: cfleming: yeah, I'm going to pull up a recent one I did to explain what I mean

22:51 cfleming: danielcompton: Well, it instruments your code, which involves macroexpanding it all using riddley. That sounds like it might introduce subtle differences in how the code works.

23:02 danielcompton: cfleming: brb

23:02 cfleming: danielcompton: np

23:28 ddellacosta: cfleming: re: cloverage, I recall it took a bit of fiddling to get it working but that may have more to do with the messy state of our codebase as anything

23:28 danielcompton: cfleming: https://dl.dropboxusercontent.com/u/5803867/Random/Screenshot%20of%20Safari%20%2826-05-15%203%3A26%3A58%20pm%29.png

23:29 cfleming: so some bits are correctly identified, and some aren't

23:29 cfleming: ddellacosta: Once you got it going, did it seem reliable?

23:29 danielcompton: cfleming: It's a good visual tool to use to go through your own code and spot bits you've missed, but I wouldn't break the build on less than 100% test coverage

23:29 cfleming: danielcompton: Thanks, that's interesting.

23:29 ddellacosta: I mean, I think so? I just use it off and on to get a sense of where we're at w/testing

23:29 I should probably be using it more often really

23:30 cfleming: danielcompton: I wonder why it misses some parts

23:30 ddellacosta: yeah, and what danielcompton sez ^

23:30 cfleming: I'm wondering if a Java bytecode coverage tool might not work better/more reliabley

23:30 *reliably

23:31 Does cloverage identify coverage of individual exprs on a single line?

23:45 danielcompton: cfleming: restarting my computer made the cljsbuild errors go away for now

23:46 cfleming: danielcompton: That's really weird.

23:51 danielcompton: cfleming: is Cursive's REPL an nREPL or something else?

23:52 cfleming: danielcompton: Well, there are two now - an nREPL one and a clojure.main one. But you're probably using the nREPL one.

23:53 justin_smith: haha, sorenmacbeth's new twitter name is Mad.MAX_VALUE

23:53 Mad/MAX_VALUE would have been more clojureish, but I'll accept it

Logging service provided by n01se.net