#clojure log - Jul 07 2012

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

0:00 duck1123: I've hit an odd issue in monger. If I insert, then find-map-by-id I get my document back. If I replace the insert with insert-and-return, I get nil. Anyone know what's up?

0:00 mthvedt: by deferring looking up symbols, rules can be immutable and you don't have any forward-declaring

0:01 duck1123: the one just calls the other, so I don't see what could be going on.

0:01 mthvedt: if you want recursive rules

0:01 i tried it the 'normal' way, and having to forward declare rules then go back and mutate the old ones, to get mutually recursive rules, just seemed… un-clojureish

0:02 grabbing the *ns* is also unclojure-ish, but IMO a lesser evil

0:02 ToxicFrog: Fair enough

0:03 Hmm.

0:03 The NPE is not limited to redefing 'name

0:03 mthvedt: yes, looks like redefining any clojure.core fn does it?

0:04 ToxicFrog: >.<

0:04 I would have thought that redefing any of those would just shadow the definition in clojure.core, since I'm in my own namespace here

0:06 mthvedt: Is the clojure team aware of this issue? It seems to be known in the google groups threads

0:07 is there a clojure JIRA or something to search?

0:07 it's known to happen in both lein and maven compilation

0:08 ToxicFrog: It does, in fact: http://dev.clojure.org/jira/secure/Dashboard.jspa

0:09 mthvedt: it does not happen except in precompiled code, so that and it being discouraged usage make it low on the radar probably

0:09 ToxicFrog: Back to Clearly for a moment -

0:09 mthvedt: ok

0:10 ToxicFrog: I'm trying to create rules for three token types. A typename is a sequence of uppercase letters; a key is any sequence of letters and numbers; and a value is any string at all not containing a newline.

0:10 In something like scala.util.parsing or flex+yacc, I'd just use regexes here.

0:10 In Clearly, I have this: https://gist.github.com/fb903793baa2e918aae0

0:10 Is there a better way to do this? Because this seems super awkward.

0:12 mthvedt: yup, clearley only eats one item of input at a time

0:12 ToxicFrog: (also, it would be really nice to be able to construct rules from regexes, specifically for this sort of thing)

0:12 So is it expected to be paired with a lexer?

0:12 mthvedt: doesn't need to be, though you can if you want to

0:13 ToxicFrog: Well, yes, it doesn't need to be, but it looks like it would make stuff like this a lot simpler

0:13 mthvedt: the earley algorithm can be modified to scan multiple items in one low-level rule… it's fairly easy, but it's nontrivial

0:13 ToxicFrog: There's a lot of code in the json parser as well working around this

0:13 mthvedt: it's on my "todo" list

0:14 try

0:14 i

0:14 instead of having 9 lines

0:14 scanner and one-or-more both return rules

0:14 * ToxicFrog ponders how hard it would be to write a rule generator that turns a regex into a rule that matches if the regex accepts the leading edge of input

0:14 mthvedt: so i think you can do (def x (one-or-more y (scanner z)))

0:15 once the rule API is cleaned up, you could just write a clearly regex parser that emits a clearly rule :)

0:15 and by you, i mean me

0:15 ToxicFrog: What is y meant to be there? I'm still a bit shaky on "rule heads".

0:16 Well, yes, I was contemplating how hard it would be for me to do, given the current state of Clearley :P

0:16 mthvedt: oh sorry

0:16 (def x (one-or-more (scanner y z))) is what i meant to type

0:16 (def sfs-type (one-or-more (scanner #(…) identity)))

0:17 try that

0:17 ToxicFrog: That works fine, thanks

0:17 And is easily macroized too.

0:18 And now that the parser compiles, my super major #1 feature request: useful error reporting when a parse fails.

0:18 This is my #1 reason for using a parsing library rather than just rolling my own recursive descent parser: error reporting.

0:20 mthvedt: yeah, about that...

0:21 i hope you don't have to throw your work away… clearly has almost no error reporting at this time

0:22 or when you say that's a feature request, you just mean, would be very nice to have?

0:23 ToxicFrog: For this project, it's not a priority, since this project is actually a rewrite of an existing codebase with no real urgency. So if I have to wait for error reporting to be added, or even add it myself, it's not a big deal.

0:24 mthvedt: ok, cool

0:24 ToxicFrog: Also because I'm the only user of this program who actually cares about parse errors, since the stuff it's processing is all machine-generated and all the end users need to do is report parse errors as a bug to me if they occur.

0:24 For projects where this is not the case, yeah, it would be a serious issue.

0:25 mthvedt: yup

0:25 one attractive thing about bottom-up parsers is error reporting is a lot more natural...

0:28 * ToxicFrog nods

0:28 ToxicFrog: For reference, errors from scala.util.parsing - which are, so far, the best I've seen - take the form:

0:28 [29.1] failure: string matching regex `= *[^\n]*' expected but `a' found

0:28 Followed by the offending line, and a carat pointing out the exact location in the line.

0:28 (this is generated by a method on the error object; all of this information can be extracted by the program easily as well)

0:29 mthvedt: i've never used scale's parsing library, but it looks very nice

0:29 isn't it top-down, though? i wonder how they make sense of errors

0:30 ToxicFrog: To be honest, I have no idea

0:30 The source is available from http://www.scala-lang.org/api/current/scala/util/parsing/combinator/Parsers.html if you feel like crowbarring it open and looking inside, although I doubt much if any of it will be relevant to an Earley parser.

0:32 Of course, it's also worth noting that the top-level Parser.scala - not even any of the concrete implements like RegexParser - is almost as large as all of Clearley including the tests

0:32 Scala's standard library is not exactly lightweight.

0:33 mthvedt: working with top-down parsers is what drove me to bottom-up parsers in the first place :P

0:33 we had a use case at work that involved a complex, highly mutually recursive grammar

0:33 existing grammars, even those that advertised the ability to handle left recursion, just all blew up

0:34 ToxicFrog: I haven't observed such issues with Scala's parsers, but I've never tried parsing anything super complex with them

0:34 mthvedt: anyway, i really gotta get some rest soon...

0:35 ToxicFrog: Ok. Now to actually fix this so that it works

0:35 Since what prompted me to mention error messages was that my parse is failing (because it does no whitespace handling at present)

0:35 Hmm. Maybe I should give it a lexer.

0:37 mthvedt: if you're too lazy to handle whitespace… s/\s+/ /g :P

0:37 ToxicFrog: mthvedt: problem with that is, note the rule for sfs-value

0:37 It's everything from the = to the end of line preserving whitespace

0:38 mthvedt: there's some whitespace rules in the json example

0:39 ToxicFrog: Yeah; it gets kind of messy.

0:40 This'll be good practice; it's been ages since I wrote a divided lexer/parser

0:40 * ToxicFrog pokes cautiously at re-seq

0:58 ToxicFrog: Huh

0:59 I can do this: #(Character/isLetterOrDigit %)

0:59 But I can't do this: (partial Character/isLetterOrDigit)

1:03 mthvedt: toxicfrog: because java methods are not clojure fns

1:04 they are actually clojure special forms

1:05 ToxicFrog: Oh :(

1:05 Am I pretty much limited to #() and equivalents for that, then?

1:06 mthvedt: pretty much

2:51 aperiodic: i think that's part of why point-free style is not really used as much in clojure--if you use #(), you don't have to keep 'is this a special form?' in the back of your mind

2:53 on a related note, i ended up writing andf & orf (the fn versions of and and or) the other day, which felt a bit odd to me

2:53 amalloy: as well it should

2:55 &(let [andf (comp (partial every? identity) list)] (andf true false))

2:55 lazybot: ⇒ false

2:55 amalloy: &(let [andf (comp (partial every? identity) list)] (andf true true))

2:55 lazybot: ⇒ true

2:55 aperiodic: man, whenever i do some thing weird with HOFs i should just come here and bug you

2:56 amalloy: my point isn't really the allegedly-clever definition of andf using comp/partial, it's that you should just use every? and some instead of andf and orf

3:02 aperiodic: the reason i ended up writing them was to construct the predicate i wanted to pass to things like every? and some

3:03 andf and orf are functions on predicates, not booleans

3:04 amalloy: so you're saying they're some-fn and every-pred?

3:05 aperiodic: yeah, that's what i'm saying

3:05 amalloy: &(doc some-fn)

3:05 lazybot: ⇒ "([p] [p1 p2] [p1 p2 p3] [p1 p2 p3 & ps]); Takes a set of predicates and returns a function f that returns the first logical true value returned by one of its composing predicates against any of its arguments, else it returns logical false. Note that f is short-... https://www.refheap.com/paste/3505

3:05 amalloy: &(doc every-pred?)

3:05 lazybot: java.lang.RuntimeException: Unable to resolve var: every-pred? in this context

3:05 amalloy: &(doc every-pred)

3:05 lazybot: ⇒ "([p] [p1 p2] [p1 p2 p3] [p1 p2 p3 & ps]); Takes a set of predicates and returns a function f that returns true if all of its composing predicates return a logical true value against all of its arguments, else it returns false. Note that f is short-circuiting in... https://www.refheap.com/paste/3506

3:50 wubino: any good reads on creating a pastebin like service?

4:05 borkdude: wubino check out https://github.com/Raynes/refheap and www.refheap.com

4:27 ro_st: are there any compelling reasons NOT to use immutant?

4:27 put another way, what's the catch?

4:28 hiredman: I wonder how well it would work in a heterogeneous environment

4:29 ro_st: ok, so one thing is you couldn't do is host on something like heroku

4:29 hiredman: in some sense it is waiting for some one to take a chance on it, I haven't heard of anyone using it "in production" yet

4:31 ro_st: it's still pretty new

4:31 hiredman: yeah, but interest is building, and it is gaining features, someone will give it a trial by fire

4:32 ro_st: not having to build out all the stuff it provides is quite compelling

4:32 hiredman: yes, but at work we've already built all that stuff :)

4:32 clojurebot: http://haacked.com/images/haacked_com/WindowsLiveWriter/IConfigMapPathIsInaccessibleDueToItsProt_1446B/works-on-my-machine-starburst.png

4:33 hiredman: a lot of features seemed to be sort of aimed at webapps instead of backend data processing apps

4:33 ro_st: perfect for us

4:33 i'm in the process of writing a json api, and shortly will be needing to port ruby/resque based stuff for messaging over

4:38 hiredman: the custering stuff would be really cool, but I would prefer to be able to swap out discovery mechanisms (just use zookeeper)

4:39 I don't trust the jgroups stuff

4:39 ro_st: i reckon it's worth playing with

4:40 gotta run!

5:22 _ulises: morning all, I have a question about midje background; basically, if I define (against-background :facts (some-fn)...) and then have (fact (f) => 1 (g) => 2), then (some-fn) is executed twice. Maybe I'm not properly understanding (fact ...) vs (facts ...)? My objective is to start a web server before running tests and to bring it down once I'm done testing. I managed to do this with (against-background :contents ...)

8:38 AWizzArd: Protocol experts wanted: I have a Protocol which I want to implement for IFns and Maps. Now, a Clojure map is at the same time an IFn. When I now call (my-proto-fn {}) I end up in the body specified for IFns. But I want to call the my-proto-fn for java.util.Maps. Ideas?

8:39 (defprotocol Bar (foos [x])) and then (extend-protocol Bar clojure.lang.IFn (foos [x] (println :fn)) java.util.Map (foos [x] (println :map)))

8:40 Now I want that (foos {}) prints :map.

9:22 daniel___: im looking for the most concise way of checking if all the values in a list equal something?

9:22 ,(map #(= % 1) '(1 2 3 4 5))

9:22 clojurebot: (true false false false false)

9:22 daniel___: ,(contains? false (map #(= % 1) '(1 2 3 4 5)))

9:22 clojurebot: false

9:23 daniel___: ,(apply #(= true %) (map #(= % 1) '(1 2 3 4 5)))

9:23 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (5) passed to: sandbox$eval87$fn>

9:23 madsy: daniel___: Maybe every?

9:23 daniel___: madsy maybe

9:24 ,(every? true (map #(= % 1) '(1 2 3 4 5)))

9:24 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.Boolean cannot be cast to clojure.lang.IFn>

9:24 daniel___: ,(every? #(= true %) (map #(= % 1) '(1 2 3 4 5)))

9:24 clojurebot: false

9:24 daniel___: :)

9:37 inklesspen: daniel___: you can just do (every? #(= % 1) '(1 2 3 4 5)) looks like. or (every? (partial = 1) '(1 2 3 4 5))

9:40 _ulises: ,(apply and (map #(= 1 %) [1 2 3]))

9:40 clojurebot: #<CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/and, compiling:(NO_SOURCE_PATH:0)>

9:41 _ulises: ,(reduce and (map #(= 1 %) [1 2 3]))

9:41 clojurebot: #<CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/and, compiling:(NO_SOURCE_PATH:0)>

9:44 _ulises: shame that and is a macro, otherwise it'd be great to reduce your checks using and

9:45 inklesspen: ,(apply (partial = 1) '(1 1 1 1))

9:45 clojurebot: true

9:46 inklesspen: ,(apply (partial = 1) '(1 2 3 4))

9:46 clojurebot: false

9:46 _ulises: lovely

9:48 AWizzArd: Well, inklesspen already showed the ideomatic solution, which is: (every? #(= 1 %) [1 2 3 4 5])

9:48 _ulises: the function equivalent to `and` is `every?`.

9:49 inklesspen: AWizzArd: is the anonymous function version any more ideomatic than the partial version?

9:49 i guess it's shorter

9:49 AWizzArd: inklesspen: both are okay, but partial is evaluated each time.

9:49 inklesspen: ah

9:49 makes sense

9:49 AWizzArd: While (fn [n] (= n 1)) is directly compiled, and thus a bit more efficient.

9:50 Plus: I personally find it more readable.

9:50 For this specific case one could do some trickery, such as (= #{1} (set [1 2 3 4 5]))

9:50 But this would just check if every element in the seq is =1

9:51 The solution with every? is more generic, and could be used as well for (every? odd? some-numbers)

10:11 ToxicFrog: Hmm. I wish I could ^Tag strings.

10:14 mthvedt: toxicfrog: good morning

10:14 ToxicFrog: 'morning

10:15 mthvedt: has the parser been working out ok?

10:16 ToxicFrog: I went to bed at about the same time as you last night; I'm just starting on the lexer now

10:16 Although I did think of a lexer-related question

10:16 mthvedt: shoot

10:16 ToxicFrog: When using defrule, a rule is of the form [terminal-or-nonterminal+], where a nonterminal is another rule, and a terminal is - when parsing a string - a single character

10:17 Eg, [\{ keyvalues \}]

10:17 How is that single character matched, and what does it need to be replaced with when parsing a stream of { :tag :foo :text "bar" } tokens?

10:17 I think that using a scanner that checks :tag would work, so you do something like:

10:18 (def open-brace (scanner #(= (:tag %) :open-brace) identity))

10:18 And then use [open-brace keyvalues close-brace]

10:18 mthvedt: matched with =

10:18 ToxicFrog: But is there a better way?

10:19 mthvedt: there's support for what i'm currently calling "tokenizers"

10:19 i

10:19 i'm not sure if they're a good idea, and might change/remove them

10:19 but basically, to test for a terminal symbol x

10:19 t

10:20 the parser runs (= x (tokenizer input))

10:20 where the default tokenizer is identity

10:21 that's still a little cumbersome, because each parse action needs to have :text in it anyway

10:22 you pass the tokenizer fn to build-parser

10:23 (build-parser goal-rule tokenizer)

10:23 ToxicFrog: Hmm

10:23 The issue I see there is that the tokenizer would (at least, I would expect) return not just the name of the input symbol but a whole bunch of information

10:24 { :tag :number :text "12.34" :line 5 :col 8 }

10:24 And for matching, you only actually care about :tag; :line and :col are for the error reporter and :text is for whatever processes the AST.

10:25 mthvedt: you could pass :tag as your tokenizer

10:25 if your input symbols are maps you want to parse the :tags of

10:27 ToxicFrog: Ok, but in that case, is the return value of the rule just the :tag, or the entire map originally passed to tokenizer?

10:28 mthvedt: the return value will be the entire map

10:29 ToxicFrog: Awesome

10:36 augustl: is it possible to access the persistent data structures from ClojureScript in a Node.js app, without converting my app to ClojureScript?

10:36 nDuff: augustl: it'll be easier to have your ClojureScript code export to native structures.

10:37 augustl: I don't have any ClojureScript code :)

10:37 * nDuff leans heavily on the tiny clj->js function in jayq.util

10:37 augustl: I could use persistent data structures though

10:37 ah, I see

10:37 nDuff: augustl: ...oh, you mean you want to _create_ them from native JS code, not just leverage them?

10:38 augustl: yes

10:38 similar to how you can create PersistentVector etc from java (right?)

10:38 nDuff: Hmm. Well, there's nothing stopping you from calling cljs.core.PersistentVector.fromArray() from native JavaScript

10:39 augustl: is cljs.core etc. available as one JavaScript file somewhere?

10:39 nDuff: augustl: ...run a compilation pass, and the output is one JavaScript file.

10:40 augustl: cool, thanks

10:40 nDuff: (when compiling with lein-cljsbuild, anyhow)

10:41 augustl: writing some code where my client for a server needs to get all state, even when it goes down

10:41 datomic-esque time semantics with persistent data would make sense for that I think

10:42 a client having to be present at all times to track state as it flows is pretty horrible. Would be much better if a client gets a ping, and then requests the state changes from time at last fetch to now

11:44 ToxicFrog: What's idiomatic for "find the first value in a coll satisfying p"?

11:45 (first (filter p coll)) ?

11:47 hyPiRion: ToxicFrog: Yeah.

11:54 ToxicFrog: I keep wanting to call it "first" or "find", but clojure already uses both of those @.@

11:58 Sorella: ToxicFrog, find-first?

12:00 ToxicFrog: Sorella: yeah, that's what I went with.

12:01 (I'm coming from a collections library which uses head/tail rather than first/rest, and (find p xs) finds the first x in xs satisfying p)

12:01 TimMc: ToxicFrog: While you're at it, you could add an optional not-found argument.

12:05 daniel___: ((a b c) (d e f) (g h i)) is there an ingenius way of testing if a = e = i?

12:05 ingenious*

12:06 or c = e = g

12:07 with pattern matching perhaps

12:07 TimMc: core.match is still extremely alpha (buggy), unfortunately.

12:08 daniel___: ,(let [((a _ _) (_ b _) (_ _ c)) ((1 2 3)(1 2 3)(1 2 3))] (println a b c))

12:08 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.lang.Exception: Unsupported binding form: ((a _ _) (_ b _) (_ _ c))>

12:08 hyPiRion: both a = e = i or c = e = g?

12:08 daniel___: yeah

12:08 hyPiRion: use vectors instead

12:08 TimMc: &(#(let [[[a] [_ b] [_ _ c]] %] [a b c]) '((1 2 3)(4 1 6)(7 8 1)))

12:08 hyPiRion: ,(let [((a _ _) (_ b _) (_ _ c)) ((1 2 3)(1 2 3)(1 2 3))] (println a b c))

12:08 lazybot: ⇒ [1 1 1]

12:08 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.lang.Exception: Unsupported binding form: ((a _ _) (_ b _) (_ _ c))>

12:08 daniel___: hyPiRion: if i had a vector of length 9?

12:09 hyPiRion: What TimMc wrote.

12:09 daniel___: cool

12:09 pattern matching only works with vectors?

12:09 TimMc: daniel___: map, nth, apply

12:09 map-indexed, really

12:10 daniel___: destructuring syntax uses vectors, but can be applied to any collection

12:10 daniel___: i c

12:10 ,(let [[[a _ _] [_ b _] [_ _ c]] ((1 2 3)(1 2 3)(1 2 3))] (println a b c))

12:10 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn>

12:10 daniel___: ,(let [[[a _ _] [_ b _] [_ _ c]] '((1 2 3)(1 2 3)(1 2 3))] (println a b c))

12:10 clojurebot: 1 2 3

12:10 daniel___: cool

12:11 TimMc: &(#(map-indexed (fn [i el] (nth el i)) %) '((1 2 3)(4 5 6)(7 8 9)))

12:11 lazybot: ⇒ (1 5 9)

12:12 TimMc: &(#(map-indexed (fn [i el] (nth el (- (count %) i 1))) %) '((1 2 3)(4 5 6)(7 8 9)))

12:12 lazybot: ⇒ (3 5 7)

12:13 daniel___: neat

12:13 TimMc: &(apply = '(3 5 7))

12:13 lazybot: ⇒ false

12:14 daniel___: any advantage over the destructuring approach?

12:14 TimMc: Extensible.

12:15 This gets you diagonals of any length.

12:15 daniel___: the disadvantage i can see is that it is less explicit, i mean it takes a few moments longer to work out what its doing

12:15 TimMc: That's why you (defn diagonal ...) and use that.

12:43 daniel___: Can anyone create a neat way of doing this, in a similarly extensible way as before? [a b c d e f g h i] -> ((a d g) (b e h) (c f i))

12:44 Perhaps there is already a function to achieve something like this, or with partition-by and map-indexed somehow?

12:44 metellus: ,(partition 3 [a b c d e f g h i])

12:44 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: a in this context, compiling:(NO_SOURCE_PATH:0)>

12:44 metellus: ,(partition 3 [1 2 3 4 5 6 7 8 9])

12:44 clojurebot: ((1 2 3) (4 5 6) (7 8 9))

12:45 daniel___: yeah, im looking at the padding

12:45 AWizzArd: alternatively (partition-all 3 your-list)

12:45 daniel___: (partition 3 3 [1 2 3 4 5 6 7 8 9])

12:45 ,(partition 3 3 [1 2 3 4 5 6 7 8 9])

12:45 clojurebot: ((1 2 3) (4 5 6) (7 8 9))

12:45 daniel___: thats not what i need

12:45 AWizzArd: ,(partition-all 3 (range 10))

12:45 clojurebot: ((0 1 2) (3 4 5) (6 7 8) (9))

12:45 daniel___: i need ((1 4 7) (2 5 8) ..

12:46 AWizzArd: ,(apply map first (partition-all 3 (range 10)))

12:46 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: clojure.lang.ArityException: Wrong number of args (4) passed to: core$first>

12:46 daniel___: ,(partition 3 3 3 [1 2 3 4 5 6 7 8 9])

12:46 clojurebot: ((1 2 3) (4 5 6) (7 8 9))

12:46 daniel___: ,(partition 3 3 3 3 [1 2 3 4 5 6 7 8 9])

12:46 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (5) passed to: core$partition>

12:47 daniel___: ,(partition 3 1 3 [1 2 3 4 5 6 7 8 9])

12:47 clojurebot: ((1 2 3) (2 3 4) (3 4 5) (4 5 6) (5 6 7) ...)

12:47 dustingetz: o you know how to map over a tree? i want to define functions like "bfs" "dfs" "iterative deepening search" that turn a tree into a lazy seq i can map over

12:47 *"does anyone know how to map over a tree"

12:47 AWizzArd: Maybe this:

12:47 (apply map list (partition 3 (range 1 10)))

12:47 dustingetz: i think this is an example in haskell: http://okmij.org/ftp/continuations/Searches.hs - but i don't understand this

12:47 AWizzArd: ,(apply map list (partition 3 (range 1 10)))

12:47 clojurebot: ((1 4 7) (2 5 8) (3 6 9))

12:47 daniel___: there we go

12:47 :D

12:47 thanks

12:48 dustingetz: yeah but i want to define functions like 'bfs' 'dfs' which control the order in which i map

12:48 metellus: ,(zipmap (partition 3 [1 2 3 4 5 6 7 8 9]))

12:48 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (1) passed to: core$zipmap>

12:48 metellus: ,(apply zipmap (partition 3 [1 2 3 4 5 6 7 8 9]))

12:48 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (3) passed to: core$zipmap>

12:48 AWizzArd: metellus: partition 2

12:49 No, nonsense. I mean: zipmap needs two args.

12:50 metellus: too bad

12:51 wingy: you think this is still valid for learning clj 1.4: https://peepcode.com/products/functional-programming-with-clojure

12:51 from 2009

12:51 hm probably not

12:51 3 years old afterall

12:53 do we have any from Stockholm here?

13:01 ohpauleez: dustingetz: Take a look at the kibit code

13:01 We use clojure.walk

13:01 and you can post and pre walk a tree

13:01 we also have a function for seq'ing the tree

13:04 dustingetz: thanks paul

13:04 ohpauleez: &(doc tree-seq)

13:04 lazybot: ⇒ "([branch? children root]); Returns a lazy sequence of the nodes in a tree, via a depth-first walk. branch? must be a fn of one arg that returns true if passed a node that can have children (but may not). children must be a fn of one arg that returns a sequence ... https://www.refheap.com/paste/3508

13:05 ohpauleez: np

13:19 weavejester: technomancy: I'm glad you pointed out "lein deploy" to me! Thanks!

13:20 ToxicFrog: I wish 'lein deploy' could deploy to github

13:21 (using the github upload-file thingy, I mean, not 'git push')

13:23 ohpauleez: ToxicFrog: There's documentation on how to host a maven repo on github, so technically ...

13:24 ToxicFrog: ohpauleez: yeah, but I don't want to host a maven repo, I just want to be able to upload release packages from the command line :P

13:39 Count number of items in xs satisfying p: (count (filter p xs)) ?

13:54 AWizzArd: ToxicFrog: yes.

14:20 wingy: why no def- like defn-

14:20 but for vars

14:21 amalloy: defn- only exists because, long ago, it was inconvenient to put :private metadata on your functions

14:21 wingy: amalloy: is it still inconventient?

14:22 amalloy: defining a new top-level name for every little thing you want to change leads to an explosion of new names: what about defmacro-? and defn-*, if we decide * should be for :dynamic?

14:22 not at all. just (defn ^:private foo [])

14:23 wingy: true

14:23 but isn't it better to just use that line then?

14:23 and remove defn- to keep things consistent?

14:24 amalloy: it's unlikely to ever get removed, for compatibility

14:24 wingy: ok

14:24 i guess convenience is good as well

14:24 amalloy: but every few months someone asks on the mailing list if they can please have def-, and the response is primarily "no, defn- is bad enough"

14:25 wingy: just like you can put a doc string with def instead of having to assign a meta doc each time

14:25 but i do think if you really want to remove something bad you can do it by deprecating it

14:26 and have it there for 1-2 more versions .. better to progress forward in the longer run

14:34 Chouser1: Anyone know why the light table sandbox might be failing for me?

14:35 The browser console says "Firefox can't establish a connection to the server at ws://localhost:8833/socket."

14:35 TimMc: Chouser1: Try chrome.

14:35 It seems to work on only some (random) versions of recent Firefoxen.

14:36 Chouser1: this is firefox 15.0a2

14:36 * Chouser1 installs chrome

14:42 Chouser1: TimMc: Thanks, chrome is working.

14:46 * nDuff rolls his own js->clj allowing a custom keyfn to be provided, and passing a depth argument to same

15:23 ssutch: what is the recommended way to provide configuration values to a compojure app?

15:23 eg, database URIs and whatnot

15:25 arohner: ssutch: you have a lot of options. Depends on the app, mainly

15:25 ssutch: my main deployment target is a uber war deployed on elastic beanstalk

15:25 that's where i want to run it

15:26 i need to provide it with db uri(s) and private keys and such

15:26 arohner: I like a bash file full of export FOO=bar

15:26 then source it before running

15:27 if you don't mind your config being checked in, you can write a clojure file that's just (def config {:foo bar}), and load that

15:28 ssutch: ok

15:28 i'm fine with providing it to the command line

15:28 i guess my only concern is things like a private key

15:29 arohner: so just export the path to the key

15:30 piotr: ssutch: hi. Env variable is the recommended way to do on Heroku. See https://devcenter.heroku.com/articles/config-vars

15:32 kmicu: ssutch: also check this out https://github.com/drakerlabs/milieu

15:33 ssutch: interesting

15:54 antares_: Spyglass now has a doc website: http://clojurememcached.info

15:55 and clojurewerkz.org has a new About page (retweets are greatly appreciated): https://twitter.com/ClojureWerkz/status/221681163641688065

16:00 daniel___: https://gist.github.com/3067920 play is my main entry point, i keep getting nullpointerexception with 'lein run'

16:00 something to do with the read-line

16:01 can anyone enlighten me?

16:02 antares_: daniel___: read-line can return nil

16:02 daniel___: yes, but its not prompting

16:03 antares_: actually, disregard, I think it returns empty strings

16:03 daniel___: do you have an example stack trace?

16:04 daniel___: added to the gist

16:06 dnolen: ,(dec nil)

16:06 clojurebot: #<NullPointerException java.lang.NullPointerException>

16:06 dnolen: daniel___: your read-int can nil

16:06 raek: how can I run a ghci repl in a cabal project?

16:07 dnolen: raek: wrong channel ;)

16:07 daniel___: I mean your read-int can return nil

16:08 daniel___: dnolen: if i take away the dec, i get an argument error

16:08 amalloy: console input doesn't work in lein run

16:08 daniel___: for some reason it isnt prompting

16:08 oh

16:08 amalloy: try lein trampoline run

16:08 daniel___: amalloy: works

16:08 :)

16:09 whats trampoline?

16:11 nvm, i see it runs it after leiningens jvm has closed

16:11 rather than in a subprocess

16:27 technomancy: antares_: we used neocons at seajure the other night; it was great

16:28 antares_: technomancy: oh, nice!

16:28 technomancy: we loaded up the clojuresphere data set into it

16:29 antares_: technomancy: big people are using clojurewerkz libraries! :)

16:29 technomancy: yeah, like me. I'm 202cm.

17:05 mjewkes: Hey Everyone. I'm running OSX with Emacs 24. I've installed lein and added 1.4.4 of lein-swank to the profiles.clj file. I've installed clojure mode in emacs and it is doing syntax highlighting properly. But emacs doesn't seem to have the clojure-jack-in command available.

17:05 Has anyone bumped into this before?

17:07 amalloy: sounds like an old clojure-mode?

17:08 mjewkes: possibly - I just installed it using package-install.

17:08 amalloy: try getting it fresh from technomancy's github

17:08 mjewkes: Interestingly - slime-connect seems to be missing to.

17:09 Should that be present - amalloy: will do.

17:09 amalloy: i dunno. i think jack-in provides its own copies of the slime libs

17:25 antares_: yes, swank-clojure bundles its own copy of slime

17:26 Pupeno_W: From https://github.com/technomancy/swank-clojure/blob/master/README.md: "Add [lein-swank "1.4.4"] to the :plugins section of either project.clj or your user profile."

17:27 What does your profile mean here?

17:27 mjewkes: ~/.lein/profiles.clj

17:27 clojurebot: /.lein/profiles.clj is nice, but it doesn't allow you to vary the profile for a specific project without checking it in to the repo

17:28 Pupeno_W: Thanks.

17:30 * ToxicFrog spends ten minutes tracking down a nullpointerexception because he changed a structure from being a list to being a map and then forgot to update one of the functions taking it as an argument ;.;

17:34 ToxicFrog: Oh bollocks

17:34 (drop n s) where s is a string returns a LazySeq

17:34 With tragic results when you're doing something like (re-match pattern (drop header-length buf))

17:37 metellus: use subs

17:37 ToxicFrog: Yeah, I was reflexively trying to make this sequence-type-agnostic

17:37 Despite the fact that, on reflection, it makes sense only for strings

18:04 overstood: I have what is hopefully a basic syntax question about Clojure, is this the right place for that?

18:05 ohpauleez: overstood: sure, totally

18:06 overstood: Great :)

18:10 So there is a function that normally it takes a number, does a thing to it and returns a value. There are some edge cases where this function needs to just return a constant because the behavior of that function is not covered by the algorithm that handles most cases. I'm currently using a lot of (if (eq input foo) constant (if (eq input foo2) constant2 (normalAlgorithm input)))

18:10 is there a better/more elegant way to do this than chaining if statements together?

18:10 ohpauleez: cond

18:11 or condp

18:11 &(doc cond)

18:11 lazybot: ⇒ "Macro ([& clauses]); Takes a set of test/expr pairs. It evaluates each test one at a time. If a test returns logical true, cond evaluates and returns the value of the corresponding expr and doesn't evaluate any of the other tests or exprs. (cond) returns nil."

18:11 ohpauleez: http://clojuredocs.org/clojure_core/clojure.core/cond

18:12 You might also want to consider `case`

18:12 http://clojuredocs.org/clojure_core/clojure.core/case

18:12 http://clojuredocs.org/clojure_core/clojure.core/condp

18:12 there's condp

18:13 overstood: That looks like what I was looking for.

18:13 Thanks a lot!

18:14 amalloy: case would work, or you could just use a map

18:15 (let [defaults {1 "one" 2 "two"}] (defn compute [x] (or (defaults x) (do-real-work x))))

18:16 overstood: that's neat too

18:16 ohpauleez: using a dispatch table like that is a pretty typical pattern overstood

18:18 mcohen: hi there #clojure. trying to get started programming Clojure and am getting stuck trying to compile, test, or repl with lein

18:19 DEBUG output shows Classpath: /Users/mcohen/.lein/self-installs/leiningen-2.0.0-preview7-standalone.jar

18:19 and everyone of those lein commands i listed above yields Exception in thread "main" java.lang.NoClassDefFoundError:

18:19 and a stacktrace

18:19 Caused by: java.lang.ClassNotFoundException:

18:19 at java.net.URLClassLoader$1.run(URLClassLoader.java:202)

18:19 at java.security.AccessController.doPrivileged(Native Method)

18:19 at java.net.URLClassLoader.findClass(URLClassLoader.java:190)

18:19 at java.lang.ClassLoader.loadClass(ClassLoader.java:306)

18:19 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)

18:19 at java.lang.ClassLoader.loadClass(ClassLoader.java:247)

18:19 Compilation failed.

18:20 i know i must be missing something simple and stupid

18:20 can anyone help please?

18:21 ohpauleez: cd to a different directly, like you $HOME

18:21 then try lein2 repl

18:21 do you still get the error?

18:21 overstood: I'm just starting to learn functional programming (I'm coming from a pretty strong OO background). It's definitely an interestint paradigm shift. I feel a bit overwhelmed by the amount of power in relatively terse statements.

18:22 Why would one use cond vs a dispatch table?

18:22 mcohen: thanks ohpauleez. nope, the repl comes up just fine if i'm not in the project dir

18:22 ohpauleez: overstood: If you needed different functions to test for different things

18:23 overstood: If you're looking for equality, dispatching via maps is usually used

18:23 (a dispatch table)

18:23 mcohen: There's an error in the source files you've written

18:23 try creating a new project with lein2 new, cd into it, and try `lein repl`

18:23 mcohen: ok, but all i did was "lein new appname"

18:24 and then lein test

18:24 i didn't edit anything

18:24 ohpauleez: there are no tests to run

18:25 overstood: so the map is basically just a bit more concise and faster than cond/case?

18:25 mcohen: test/<project_name>/core_test.clj

18:25 is created when i did lein new app

18:25 ohpauleez: more concise and preferred in that case (if you're just checking for equality). I'm not sure about performance

18:26 mcohen: And what's in that file?

18:26 overstood: ohpauleez: got it, thanks

18:26 mcohen: (ns congo.core-test

18:26 (:use clojure.test

18:26 congo.core))

18:26 ohpauleez: overstood: No problem!

18:26 mcohen: (deftest a-test

18:26 (testing "FIXME, I fail."

18:26 (is (= 0 1))))

18:26 ohpauleez: mcohen: try creating a new project and see if the errors happen in the new project

18:27 mcohen: yeah, i tried that already actually.

18:27 when i run with the DEBUG flag on it prints Classpath: /Users/mcohen/.lein/self-installs/leiningen-2.0.0-preview7-standalone.jar

18:27 but if i run lein classpath, i get

18:28 overstood: one more question, are there any good resources to learn more about performance in clojure. I'm specifically interested in memory allocation. I want to try writing a little game for Android which means I want to try to avoid GC collection if I can.

18:29 dnolen: overstood: Clojure's design assumes GC, it's pretty hard to avoid

18:30 overstood: Even more specifically, when I'm using Clojure functions that don't have side effects. What is allocated and when is it released?

18:32 amalloy: overstood: consider a simple case where x is the list (1 2 3)

18:32 if you compute (cons 4 (rest x)), you get back (4 2 3). that list shares the 2 and 3 elements (and the list pointers linking them together) with the original

18:33 so the head of the x list is no longer needed (assuming you don't have a reference to x anymore), and it's thrown away, GCed whenever the JVM finds it convenient

18:35 stain: anyone played with the framebuffer (/dev/fb0) from Clojure?

18:35 * nDuff somewhat doubts it.

18:35 mcohen: so if you run lein <command> in the root of your clojure project with DEBUG=1 what will be shown as the Classpath variable?

18:36 or, what should be shown?

18:36 all i see is /Users/mcohen/.lein/self-installs/leiningen-2.0.0-preview7-standalone.jar

18:36 but if i run lein classpath then it does in fact list out the jars i've included as dependencies

18:36 as well as the src, test, resources, dev-resources, and classes dirs

18:37 but the ClassNotFoundException feels like i must have a classpath issue somewhere

18:38 overstood: amalloy: That makes parfect sense. I'm still trying to get an intuitive grasp of the implications of immutable state. Thanks!

18:52 casperc: hello

18:52 I have this question which is not really clojure specific, but I thought you might be able to help anyway

18:53 I want to start a clojure process which starts an embedded jetty server at a random port. Then I want to have that port returned to my so I can run som tests against my api

18:53 anyone know how to go about this?

18:54 jeremyheiler: ,(rand-int 100)

18:54 clojurebot: 24

18:55 jeremyheiler: casperc: you can also check out the ring-jetty-adapter to see how it starts a jetty server.

18:55 https://github.com/mmcgrana/ring/blob/master/ring-jetty-adapter/src/ring/adapter/jetty.clj

18:55 casperc: I want to do this to be able do some cucumber/soapui tests against the api as part of ci

18:56 stain: casperc: ring can do that

18:56 I just type "lein ring server" and it pops up a browser window

18:56 casperc: jeremyheiler: i should clarify, I know how to start the jetty at a random port. What I don't know is how to get that random port returned to the rake script starting the process

18:56 stain: I think it just tries to bind to port 3000, if it is taken, add 1, etc

18:57 jeremyheiler: casperc: how are you invoking the process?

18:57 better yet, how do you want to invoke the process? at a repl?

18:58 casperc: doesn't really matter actually, the imortant bit is that the jetty server is started and the port returned so I can run api tests again it externally

18:59 multiple tests and builds might be running at the same time, so it can't be the same port always

19:01 actually, come to think of it, the correct way may by for the invocing process to supply the port, not the clojure process to return it

19:02 jeremyheiler: something like this? (let [port (random-port)] (start-jetty-server port) port) which would then return the port number taht you can write to std out or whatever you need to put it.

19:04 casperc: jeremyheiler: that might work

19:05 I think i will try it the other way around though and have the script starting the process supply the port. Thanks for the input :)

19:05 jeremyheiler: casperc: no problem. good luck

19:06 casperc: thank you

19:14 AWizzArd: Hmm, interesting: at runtime I load a file. This file contains key/value pairs. I now want to implement a macro (with-file "c:/my.file" body). I want that with-file is like an implicit let, where the bindings represent those key/value pairs, so that I can refer to them in the body.

19:15 Example: in the file I have this map: {:a 1, :b 2, :c 3}. Now I want that (with-file "c:/my.map" (= c (+ a b))) expands to code that will eval to “true” at runtime. I think this could be a case for valid use of “eval”. Opinions?

19:16 nDuff: AWizzArd: Err. Do you want the file to be read at compile time or runtime?

19:16 AWizzArd: ...keeping in mind that macro expansion happens at compile time...

19:17 * nDuff would generally take a position of "Don't Do That".

19:17 AWizzArd: I want to read the file at runtime.

19:17 nDuff: AWizzArd: ...what you want can't be done without forcing the code within the macro to be recompiled every time it's executed. That's pretty evil.

19:18 AWizzArd: is it really _that_ much harder to put the read contents of the file in a variable and refer to (:a my-var) rather than just "a"?

19:18 AWizzArd: nDuff: yes

19:18 * nDuff shrugs, and wanders off.

19:18 AWizzArd: That’s why Clojure offers destructuring.

19:19 I want runtime destructuring of files.

19:19 nDuff: ...sure, but destructuring as it's typically done doesn't impact runtime performance, at least not to the scale you're talking about here; it's a very different tradeoff.

19:19 * nDuff makes good on the walking-away bit, really.

19:19 amalloy: AWizzArd: no, you want destructuring with unknown keys

19:20 ignore the "file" part of this entirely - then you're asking for (with-map m body), where body is evaluated with all the locals in m implicitly bound

19:20 AWizzArd: Yes.

19:20 amalloy: which is totally possible and not even hard, but pretty disastrous as an idea

19:20 nDuff: ...even though the code may not even _compile_ if the file doesn't contain the keys it needs/expects.

19:21 AWizzArd: amalloy: not hard… without using eval?

19:21 nDuff: Actually -- this is silly. Your code knows which keys it needs.

19:21 amalloy: no, you of course have to use eval

19:21 AWizzArd: Yes, I agree.

19:21 nDuff: So, you can just assume that those keys will be present in the file, and use _real_ destructuring.

19:22 AWizzArd: amalloy: Pretty trivial, just wanted to check if I might have missed something to make this happen without eval.

19:22 nDuff: ("real", meaning compile-time)

19:22 amalloy: read over http://stackoverflow.com/questions/9345056/in-clojure-how-to-destructure-all-the-keys-of-a-map before you really commit to doing something that i think is a mistake

19:23 nDuff: AWizzArd: Why can't you use real, fixed-key destructuring, with the set of keys that map to what the code uses?

19:23 AWizzArd: After all, you aren't proposing that the code changes, only that the file does.

19:23 AWizzArd: Well, I have nearly 10 years Lisp experience, and I am aware of the multitude of problems.

19:24 nDuff: AWizzArd: ...so there's quite literally no point at all to the extra pain you're wanting to create.

19:25 AWizzArd: nDuff: The whole purpose is to not have to manually extract those keys.

19:25 It is a pure convenience importer macro.

19:25 nDuff: AWizzArd: not to extract them from the code, as opposed to from the file, right?

19:25 AWizzArd: For FXML files ==> JavaFX

19:25 nDuff: AWizzArd: So you can just have your macro analyze the code at compile time; done.

19:25 amalloy: oh god

19:25 AWizzArd: Yes?

19:25 clojurebot: yes isn't is

19:25 amalloy: that's even worse, nDuff

19:26 Raynes: I think the point amalloy is trying to make is that this is a convenience to you and a terrible, terrible inconvenience to anyone who ever reads your code or works with it, including future you.

19:26 You don't want this. Stop before it is too late.

19:26 amalloy: *shrug* we put up the signposts, he disagrees, and the language gives him a way to do it

19:26 AWizzArd: Plus I think it may turn out useful.

19:27 amalloy: *nod* if you're doing it as a general-purpose macro where you don't know what the code is or what the config file contains, that's interesting. still has problems, but isn't obviously loony

19:27 AWizzArd: Well, I read a fxml file, and get a hashmap. The keys are keywords, and the values are JavaFX components.

19:28 amalloy: keywords? if they're supposed to represent symbols, and you're reading the file rather than eval'ing it, it makes more sense to store symbols as keys

19:29 AWizzArd: I am really saving a (let [username-label (:username-label fxml), password-label (:password-label fxml), username-text (:username-text fxml) …)

19:29 A bigger program with several UIs would require always a 20 line let in the setup functions. This can be reduced to a one-liner.

19:30 (with-fxml ["login-ui" "email-ui"] body)

19:31 This is actually nicer than a 21 line let.

19:31 But yes, if this turns out to be too problematic, I will remove it before a 1.0.

19:33 Also that macro can type-hint all those symbols, so calling into .methods will do no reflection. Type hints are really required, since the UI thread should not be slowed down from reflection.

19:41 Trivial, thanks to Clojure’s power: (mapcat (fn [[k v]] [(with-meta (symbol (name k)) {:tag (class v)}) v]) my-map)

19:48 amalloy: uhhhhh, is that going to work? it's hard to imagine values for v where the class can be usefully typehinted and the value can be embedded into code

19:50 AWizzArd: The values are Buttons, Labels, TextFields, etc.

19:51 amalloy: i don't think you'll be able to embed those in code

19:51 AWizzArd: And in the body one wants to do things such as (.setText password "").

19:52 amalloy: try it: (defmacro let-button [& body] `(let [~'button ~(make-button-object)] ~@body))

19:52 AWizzArd: Useful when we get a (let [^PasswordField password (:password fxml)] …)

19:53 instead of ~'button it should probably be something like ~(with-meta 'button {:tag Button})

19:53 amalloy: AWizzArd: yes, but that's not relevant to my objection

19:53 AWizzArd: Then I don’t understand it yet. Could you say it in other words?

19:55 amalloy: AWizzArd: either v is a Button object, or it's code that you could evaluate to produce a Button

19:55 if the former, then you can't embed it as part of the let statement

19:55 if the latter, you won't have its class yet

19:56 also, you want {:tag `Button}, not {:tag Button}; tags are symbols, not classes

19:57 AWizzArd: Yes, it was just a sketch.

19:57 I will experiment with this now.

20:01 amalloy: I can go around this by not taking the (class v) but (class (eval v)).

20:01 The interesting thing here is though that the symbols that end up in the body, are different from the ones in the let.

20:02 amalloy: i don't understand that last

20:03 AWizzArd: amalloy: try this: (defmacro bar [m & body] (let [lala (mapcat (fn [[k v]] [(with-meta (symbol (name k)) {:tag (class (eval v))}) v]) m)] `(let [~@lala] ~@body)))

20:04 amalloy: then in the repl: (def x (macroexpand '(bar {foo (:lup {:lup "Hi"})} (.length foo))))

20:05 (-> x second first meta) ==> String, but (-> x last last meta) ==> nil

20:05 amalloy: of course

20:05 AWizzArd: Although when you try both -> forms without the last meta, you will both times see it is foo.

20:05 amalloy: just like without a macro

20:05 AWizzArd: But also that can be solved :-)

20:05 amalloy: what? don't solve it

20:05 it's not a problem

20:06 AWizzArd: Why not? I want those type hints.

20:06 amalloy: no you don't

20:06 (let [^Foo x 1] x) - nobody writes (let [^Foo x 1] ^Foo x), because there's no reason

20:06 AWizzArd: Turn on reflection warnings, and you will see that (bar {foo (:lup {:lup "Hi"})} (.length foo)) throws a warning.

20:07 I want that the vars in the body inherit the type hints from the let.

20:07 So I need the identical (hinted) symbols in the body.

20:07 amalloy: no you don't

20:07 they always inherit

20:07 the problem is still what i said: tags are symbols, not classes, and you're trying to use a class

20:08 AWizzArd: Ah, right.

20:08 Good point.

20:09 Yes, works.

20:10 Lot’s of evals, but currently I still think this is a valid use case for it. I am thankful for the scepticism to use it, but I want to remind that I am the guy who invented scepticism against the use of eval.

20:11 amalloy: shit, really? i thought you were dead, mister mccarthy

20:11 AWizzArd: ;)

20:12 In fact, so far my only real usecase for it was my Genetic Programming lib, where it is obviously the right choice.

20:12 (as the whole point is the creation of code at runtime, and then run it)

20:40 dyba: Should I be expecting an OutOfMemoryError when using (range) ?

20:40 I understand (range) creates a lazy sequence from 0 to positive infinity

20:40 AWizzArd: Fortunately range is lazy, as you said.

20:40 dyba: but I guess I don't quite understand what lazy means

20:40 AWizzArd: So it will only produce those numbers when they are needed.

20:41 dyba: so I shouldn't be expecting an out of memory error, correct?

20:41 AWizzArd: Yes.

20:41 Just don’t keep a pointer to the begin of the sequence.

20:41 dyba: the only string i get explaining the error is Java heap space

20:42 my test is currently failing

20:42 AWizzArd: (doseq [n (range)] (when (= n 9999999999999) (System/exit 0))) will run fine, without killing the RAM. It would run a long time though.

20:43 dyba: AWizzArd: I was just running a simple test to make sure I understand what to expect from using range

20:43 inside a test I wrote:

20:43 (is (= 0 (range)))

20:44 but that's not quite correct, it should fail

20:44 but i got a failure for a different reason, i.e. OutOfMemory

20:44 AWizzArd: so would your approach be a better way to test what I had in mind?

20:47 AWizzArd: Well, (range) is a sequence of numbers.

20:47 The 0 is one of them.

20:47 But “a sequence of numbers” is not equal to the number zero.

20:48 But (is (= 0 (first (range)))) should succeed.

20:48 dyba: right

20:49 ToxicFrog: <dyba> but I guess I don't quite understand what lazy means - lazy seqs evaluate each element only as needed. (take 5 (range)) evaluates only the first five elements in the seq, even though the seq is, in principle, infinite.

20:50 AWizzArd: amalloy: it is in fact very exciting how easy this is in Clojure. Java developers who want to work with FXML will have to manually extract all their components which they want to refer to in event handlers.

20:50 That option is still available in my lib, and it also has advantages. But being able to automtically import them is a very nice feature.

20:50 dyba: ToxicFrog: so (range) shouldn't return anything because I haven't carried out any operations on it?

20:50 ToxicFrog: Depends on what you do with it

20:51 (= 0 (range)) might actually evaluate the entire sequence as it tries to do the compare.

20:51 dyba: ah I see, hence the OutOfMemory error

20:52 aamar: dyba: it also might be the clojure.test framework creating the error, as it tries to inform you why the equality comparison failed.

20:53 ToxicFrog: Yeah, in that case it might try to evaluate the seq so that it can print it or something.

20:53 And then boom.

20:53 dyba: aamar: I believe you are right, I would have to see what = is doing under the covers

20:53 aamar: I suspect it's that, because (if (= 0 (range)) 1 2) works fine for me

20:53 ToxicFrog: Alright then

20:54 AWizzArd: ,(= 0 (range)) ; = does not traverse the whole range

20:54 clojurebot: false

20:55 dyba: thanks <ToxicFrog>, <aamar>, <AWizzArd>!

20:56 oh so it's probably the 'is' in the testing clojure.test framework

20:57 AWizzArd: That may be it.

20:58 Though I would find that a bit surprising.

21:08 dyba: range doesn't look like it's capable of handling floats correctly, am I correct?

21:08 AWizzArd: What means “handling floats”?

21:08 dyba: I just tried (range 1.0 2.0 0.2) and it didn't quit get to 1.6

21:08 it gave me 1.5999999

21:09 it gave me (1.0 1.2 1.4 1.59999... 1.79999... 1.99999...)

21:09 AWizzArd: dyba: You would like to read http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

21:10 “What Every Computer Scientist Should Know About Floating-Point Arithmetic”

21:10 dyba: AWizzArd: will do, I'll check it out right now

21:10 AWizzArd: It is a pretty long read, but important stuff in there.

21:11 ,(range 1 2 1/5)

21:11 clojurebot: (1 6/5 7/5 8/5 9/5)

21:11 dyba: AWizzArd: Ah ha! you used a rational

21:11 I forgot about those in Clojure

21:12 AWizzArd: Although 1.5999999 is as close as you can get to 1.6, when you just can express 4 billion different numbers (i.e. floats).

21:13 You have only 2^32 numbers available (4 billion), as floats have to encode those numbers in 32 bits.

21:17 Frozenlock: Is there some mechanism to install and auto-run a clojure app at each reboot? (Or is this more of a java question?)

21:18 AWizzArd: dyba: the engineers who implemented this had a pretty hard job. Out of all numbers they had to choose 4 billion that can be expressed with a float. Obviously nearly all numbers had to be excluded. They concentrated on numbers that are typically interesting to scientists.

21:18 Frozenlock: more a question of your operating system.

21:19 Frozenlock: True. Let's say a windows machine. I already use launch4j to wrap my jars, but I would like a proper installation.

21:19 AWizzArd: dyba: what you can do though is not using the floating-point unit that ships with your mainboard, but instead use a java.math.BigDecimal, which has a different representation and allows for much more precision.

21:20 dyba: in Clojure there is even a reader syntax for such numbers. Just append an uppercase “M”:

21:20 ,(range 1.0M 2.0M 0.2M)

21:20 clojurebot: (1.0M 1.2M 1.4M 1.6M 1.8M)

21:22 AWizzArd: Frozenlock: this is a not so trivial issue and has not really to do with Clojure or Java. You should try in #Windows. If you know about Windows Services you might be interested in http://yajsw.sourceforge.net/

21:22 Frozenlock: it will probably take you 3-15 hours to get this working.

21:22 Frozenlock: Hmmmm so adding the Frozenlock effect, I should count 48 hours :P

21:23 Thanks, I'll take a look!

21:23 AWizzArd: But a very simple way would be to run a .bat file on reboot. In that file you have a line such as: start java -jar c:/users/frozenlock/Desktop/nice-tool.jar

21:24 That’s a fast and nice way for small admin UIs and such. But professional server software should really run as a Service.

21:24 Frozenlock: Yeah it does sound hacky- but for a proof of concept it might be enough. Thank you very much!

21:27 dyba: AWizzArd: I'll look into that, thanks!

21:32 ToxicFrog: God, I hate deploying on windows.

21:38 dyba: ToxicFrog: are you doing that for work?

21:40 ToxicFrog: dyba: no, but one of my current projects is designed to integrate with a game released on windows and OSX

21:40 So it needs to work on windows

21:49 dyba: AWizzard: yup, the BigDecimal instance works better for the use case I had brought up

22:01 evildaemon: I'm not quite sure I understand the "lists" model of data processing.

22:01 I know all the data structures are immutable. But I'm not sure how to build new lists out of the old ones.

22:04 As an example, if I try to use conj to build a new list, I get a list bubble and then the contents of the other list.

22:04 Cons does the same thing.

22:04 ToxicFrog: How are you using them?

22:04 ,(cons 1 '(2 3 4))

22:04 clojurebot: (1 2 3 4)

22:05 evildaemon: ToxicFrog: Thank you.

22:05 ToxicFrog: ,(cons '(2 3 4) 1)

22:05 clojurebot: #<IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long>

22:05 ToxicFrog: Whups

22:05 ,(cons '(2 3 4) '(1))

22:05 clojurebot: ((2 3 4) 1)

22:05 evildaemon: lol.

22:06 Wait, isn't it kind of dangerous to have a clojure interpreter just sitting in the IRC channel?

22:07 ToxicFrog: Pretty sure it's sandboxed so that you can't actually damage anything

22:07 ,(println (range))

22:07 clojurebot: (0 1 2 3 4 ...)

22:07 ToxicFrog: ,(dorun (map println (range)))

22:07 clojurebot: Execution Timed Out

22:08 evildaemon: ToxicFrog: I suspected as much, couldn't see how the channel wouldn't be spammed to death by recursive functions otherwise.

22:09 ToxicFrog: ,(dorun (map println (range 1 100)))

22:09 clojurebot: 1

22:09 2

22:09 3

22:09 4

22:09 5

22:09 ToxicFrog: Oh god

22:09 clojurebot: 6

22:10 7

22:10 8

22:10 9

22:10 10

22:10 ToxicFrog: I'm so sorry

22:10 clojurebot: 11

22:10 12

22:10 13

22:10 14

22:10 15

22:10 16

22:10 17

22:10 18

22:10 19

22:10 20

22:10 21

22:10 ToxicFrog: I should have PMd that

22:10 clojurebot: 22

22:10 23

22:10 24

22:10 25

22:10 26

22:10 27

22:10 28

22:10 29

22:10 30

22:10 31

22:10 32

22:10 33

22:10 TheBusby: nice, like times of old

22:10 clojurebot: 34

22:10 35

22:10 36

22:10 37

22:10 38

22:10 39

22:10 40

22:10 ToxicFrog: evildaemon: it's not nearly as well sandboxed as I thought :/

22:10 clojurebot: 41

22:10 42

22:10 43

22:10 44

22:10 45

22:10 46

22:10 47

22:10 48

22:10 49

22:10 50

22:10 51

22:10 52

22:10 53

22:10 54

22:10 55

22:10 56

22:10 57

22:10 ToxicFrog: Also, I should have tested with (range 1 5)

22:10 clojurebot: 58

22:10 evildaemon: Goddamit.

22:10 clojurebot: 59

22:10 60

22:10 61

22:10 62

22:10 63

22:10 64

22:10 65

22:10 66

22:11 67

22:11 Frozenlock: That's funny

22:11 clojurebot: 68

22:11 69

22:11 70

22:11 71

22:11 72

22:11 73

22:11 74

22:11 75

22:11 76

22:11 Frozenlock: Isn't there a time limit for clojurebot?

22:11 clojurebot: 77

22:11 78

22:11 evildaemon: I'm sorry I said anything.

22:11 clojurebot: 79

22:11 80

22:11 81

22:11 82

22:11 83

22:11 84

22:11 85

22:11 86

22:11 87

22:11 88

22:11 89

22:11 90

22:11 91

22:11 92

22:11 93

22:11 94

22:11 95

22:11 96

22:11 97

22:11 98

22:11 99

22:11 ToxicFrog: Feature request for clojurebot: combine multiple lines of output into single IRC message; restrict the number of messages a single command can emit.

22:11 evildaemon: Yes.

22:12 Frozenlock: At least now we know.

22:12 evildaemon: What? No one ever tried that before?

22:12 TheBusby: an knowing is half the battle?

22:13 Frozenlock: Yup, now we know who the enemy is :)

22:13 ,flame ToxicFrog

22:13 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: flame in this context, compiling:(NO_SOURCE_PATH:0)>

22:13 Frozenlock: What, no flame bot?

22:14 ToxicFrog: Frozenlock: there is a time limit, but apparently that didn't hit it!

22:14 evildaemon: (defn 787 (print 5))

22:14 ,(defn 787 (print 5))

22:14 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: Parameter declaration print should be a vector>

22:15 evildaemon: Oh right, arguments.

22:15 Frozenlock: I think defn is forbidden as a protection

22:15 Isn't it?

22:15 evildaemon: (defn 787 [] (print 5))

22:15 ,(defn 787 [] (print 5))

22:15 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IObj>

22:15 ToxicFrog: ,(defn foo [x] (println x)) (foo 1)

22:15 clojurebot: #<Exception java.lang.Exception: SANBOX DENIED>

22:15 ToxicFrog: Yep.

22:15 evildaemon: Ah.

22:15 ToxicFrog: SANBOX.

22:15 evildaemon: Interesting.

22:16 So I would assume that def and fn are blocked as well?

22:16 Frozenlock: Hopefully

22:20 evildaemon: ,(def test556 9)

22:20 clojurebot: #<Exception java.lang.Exception: SANBOX DENIED>

22:20 Frozenlock: , (map (fn [a] (print a)) [1 2 3 4])

22:20 clojurebot: (1234nil nil nil nil)

22:20 Frozenlock: wut

22:21 evildaemon: lol.

22:21 Frozenlock: It does the same thing on my repl....

22:21 What am I missing here

22:21 evildaemon: Oh dear.

22:22 Frozenlock: , (map (fn [a] a) [1 2 3 4])

22:22 clojurebot: (1 2 3 4)

22:23 Frozenlock: Oh I see... Print send them to *out* (which is the repl), the return nil for everyone of them.

22:23 *then

22:24 evildaemon: I love how the last github commit is entitled: "Should have thought this through."

22:24 arohner: is there a library like trammel that can be used to provide "inheritance" for fn contracts?

22:25 Frozenlock: evildaemon: Funny, but kinda lack precision

22:25 arohner: I'd really like to define a contract for a class of fns, and then define new fns, that match the same contract

22:26 and it'd be amazing if at least part of it was verified at compile time

22:41 evildaemon: ,(print "(+ 2 2)")

22:41 clojurebot: (+ 2 2)

22:42 evildaemon: ,(print ",(+ 2 2)")

22:42 clojurebot: ,(+ 2 2)

22:47 Frozenlock: Ok I'm doing it, jumping to lein 2 and clojure 1.4, wish me luck!

22:47 * Frozenlock opens the forbidden box

22:48 evildaemon: ToxicFrog: How do I do that with named lists?

22:49 ToxicFrog: evhan: "named lists"?

22:50 evildaemon: ToxicFrog: You know, lists that have symbols attached with def or let.)

22:50 ToxicFrog: Er

22:50 tos9: evildaemon: I checked that :)

22:50 evildaemon: It's amazing how many bots are vulnerable to that sort of exploit.

22:51 ToxicFrog: evildaemon: you're going to have to explain in more detail what you're trying to ask

22:52 evildaemon: tos9: I didn't feel like pushing it, but I briefly thought: "I wonder if I look at the source I'll discover that trick will work if you append a users name and timestamp before it."

22:53 ToxicFrog: (def r (list 7 7 6 5 0))

22:53 Not sure what it's actually called.

22:53 ToxicFrog: Ok, in that case, what is the "that" that you want to do?

22:57 evildaemon: ToxicFrog: This could take while.

22:58 ToxicFrog: evildaemon: I mean, it looks like you're asking "how do I print a list by name" but that's the same as anything else - (def r '(1 2 3 4 5)) (println r)

22:58 So you must be asking something else

22:59 evildaemon: ToxicFrog: How do I combine two lists?

23:00 mindbender: anyone using counterclockwise here?

23:01 ToxicFrog: evildaemon: depends on what you mean by "combine", but probably (concat xs ys)

23:01 ,(concat '(1 2 3) '(4 5 6))

23:01 clojurebot: (1 2 3 4 5 ...)

23:01 ToxicFrog: evildaemon: also, it sounds like you need this: http://clojure.org/cheatsheet

23:01 It is damn useful.

23:02 evildaemon: ToxicFrog: Yes.

23:37 mindbender: with counterclockwise I'm having trouble importing a github project, need I install git for eclipse

23:37 ?

23:41 acristin: mindbender: I haven't installed git for eclipse, and I have been able to import github projects that I had cloned through the git commandline tool, but I think eclipse copied the whole directory into my workspace. I'm not sold on counterclockwise yet, so I didn't really try very hard

23:44 mindbender: acristin: ok.. I'm still exploring too and wondering why it won't even recognize my cloned repo in the first place but I'm corresponding with Laurent, a top maintainer of ccw, thanks for sharing your experience!

23:53 ssutch: is it possible to def a function that can respond differently to different keyword arguments, eg

23:54 ,(defn a ([{a1 :a1}] ("something")) ([{a2 :a2}] ("something else"))

23:54 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.RuntimeException: EOF while reading>

23:54 ssutch: ,(defn a ([{a1 :a1}] ("something")) ([{a2 :a2}] ("something else")))

23:54 clojurebot: #<Exception java.lang.Exception: SANBOX DENIED>

23:54 ssutch: bajh

23:55 "cant have 2 overloads with the same arity" is what it should print

Logging service provided by n01se.net