#clojure log - Apr 10 2011

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

0:11 danbell: I'm having trouble getting an example app to run through Tomcat;

0:12 since clojure compiles straight to bytecode, it's hard to make sense of the stacktrace

0:12 any general tips?

0:12 mec: would (eval `(~x ~@args)) be particularly slower than (apply x args)

0:14 livingston: mec: i dont' know about in clojure but there are other considerations such as lexical scope when using eval in commonlisp

0:14 is there a good reason not to use apply?

0:14 mec: x could be a macro

0:15 well seems to be about 21 times slower

0:15 livingston: is it a function some is passing you? just make them pass you a function version or something.

0:16 amalloy: i've actually found a good (i think) reason to use that eval form, but in general it's a terrible idea

0:16 livingston: there's an expression "eval is evil" it isn't and the basis for the expression is bad, but in general it's best to avoid it.

0:16 same for macros, if there a reason to use them fine, but if a function fits, use that.

0:17 sure there can be plenty of good reasons. lazy is a bad one though ;)

0:17 amalloy: danbell: (1) look for entries in the stacktrace that contain myproj.myns. most of the interesting ones will look like that. (2) as with any java stacktrace, the "root cause" exception is often most related to your code. look for "caused by": the last instance of that is the root cause

0:18 danbell: amalloy, as usual, is ridiculously helpful

0:18 amalloy: there's also clj-stacktrace, which purports to make stack traces more readable

0:30 mec: out of curiosity, what are the circumstances that make you want to use eval like that?

0:30 mec: playing around with findfn

0:30 amalloy: haha, that explains why you saw that eval form, i guess

0:30 livingston: I just tried to comment something out in java with a semicolon. it compiled I thought i was good then got really confused. (you can put as many extra semicolons in between statements as you want)

0:32 amalloy: while (x < 10);

0:32 x++;

0:33 the semicolon of doom

0:33 livingston: ok maybe not there. but that's your fault for not using squigglies

0:34 amalloy: livingston: well, that's not "in between statements", so your claim is still true

0:34 livingston: that's why sexpressions and prefix notation win again ;)

0:34 I guess that's true too

0:34 mec: ,(apply #'and [1 2])

0:34 clojurebot: true

0:34 mec: why does that return true

0:35 amalloy: $source and

0:35 sexpbot: and is http://is.gd/pY0AD3

0:36 amalloy: &(#'and)

0:36 sexpbot: java.lang.IllegalArgumentException: Wrong number of args (0) passed to: core$and

0:36 livingston: lol

0:36 mec: weird

0:37 amalloy: mec: it's calling the function behind the and macro, with 1 as &env, 2 as &form, and no "actual" args

0:37 &(#'and 1 2 3)

0:37 sexpbot: ⟹ 3

0:37 amalloy: &(#'and false false 3)

0:37 sexpbot: ⟹ 3

0:38 mec: crazy

0:39 livingston: ,(macroexpand '(apply #'and [1 2]))

0:39 clojurebot: (apply (var and) [1 2])

0:39 mec: ,(apply #'and nil nil [true true false])

0:39 clojurebot: (clojure.core/let [and__3468__auto__ true] (if and__3468__auto__ (clojure.core/and true false) and__3468__auto__))

0:40 mec: ok so i guess i'll stick with eval

0:40 amalloy: mec: you definitely won't get what you want by applying a macro

0:40 livingston: you're quoting a macro

0:41 amalloy: i guess that's not true. you might want crazy, unpredictable results

0:41 mec: i enjoy living on the edge

0:42 pdk: if you want crazy unpredictable results

0:42 try some c++ multithreading libraries

0:43 livingston: I have enough fun with java and it's dumb libraries, I don't need to go back to freeing memory too, thanks.

0:44 mec: i suppose it makes sense that the only way to expand a macro at runtime is with eval

0:45 livingston: macros are processed at read time. it doesn't know what to do if you try to fn'call one.

0:47 amalloy: livingston: otoh, they are just functions underneath, which is why ##(#'and nil nil x y) is the same as ##(macroexpand '(and x y))

0:47 sexpbot: ((var and) nil nil x y) java.lang.Exception: Unable to resolve symbol: x in this context

0:47 (macroexpand (quote (and x y))) ⟹ (let* [and__3468__auto__ x] (if and__3468__auto__ (clojure.core/and y) and__3468__auto__))

0:48 amalloy: &(#'and nil nil 'x 'y)

0:48 sexpbot: ⟹ (clojure.core/let [and__3468__auto__ x] (if and__3468__auto__ (clojure.core/and y) and__3468__auto__))

0:49 livingston: how do I ask an object what interfaces it implements?

0:50 amalloy: sure it's a function, but it's a function that returns code

0:50 amalloy: &(supers (class []))

0:50 sexpbot: ⟹ #{java.util.List clojure.lang.AFn java.lang.Object java.io.Serializable java.lang.Runnable java.util.Collection clojure.lang.APersistentVector clojure.lang.Seqable clojure.lang.Indexed clojure.lang.Reversible clojure.lang.Sequential clojure.lang.IPersistentStack cloj... http://gist.github.com/912053

0:51 livingston: er, sexpressions really that are then stitched into the code

0:51 amalloy: or if you want to test implementation of a particular interface, ##(instance? Runnable [])

0:51 sexpbot: ⟹ true

0:52 livingston: that got me what I needed. I need to see what interfaces where available on a clj object so that I knew what were my options to tell stupid-java to cast it to

0:52 thanks

0:52 ssideris: amalloy: wait, why is [] Runnable???

0:52 amalloy: ssideris: because it's a function

0:53 mec: ,([1 2[ 0)

0:53 amalloy: &([1] 0)

0:53 clojurebot: Unmatched delimiter: )

0:53 sexpbot: ⟹ 1

0:53 mec: doh

0:53 amalloy: haha clojurebot looks like he's laughing at you

0:53 ssideris: amalloy: thanks, didn't know that!

0:53 livingston: ,(

0:53 clojurebot: EOF while reading

0:54 livingston: I was hoping to get him to frown

0:54 amalloy: &([1 2[ 0)

0:54 sexpbot: java.lang.IllegalArgumentException: Wrong number of args (0) passed to: PersistentVector

0:54 amalloy: heh

0:54 mec: lolwut

0:54 amalloy: sexpbot tries to clean up unbalanced expressions

0:54 looks like the one he cleaned up caused some problems

0:55 &(let [x 1) (inc x)

0:55 sexpbot: ⟹ 2 ; Adjusted to (let [x 1] (inc x))

0:56 ssideris: so basically nth is only necessary for lazy sequences like ##(nth (range 10) 2)

0:56 sexpbot: ⟹ 2

0:57 amalloy: ssideris: or for lists, or for cons chains, or for j.u.Lists, or...really anything but vectors

0:57 ssideris: ok

1:15 livingston: how can people program without repl? change, compile, run, *damn*, GOTO 10 ... this takes forever

1:23 mec: i dont know how i ever programed without doc and source

1:24 livingston: mec: show is the biggie for me in the repl

1:25 programming in java is for the birds though - of all things it just yelled at me for giving it too much type information. gah.

1:25 amalloy: haha clarify plz livingston?

1:26 livingston: amalloy: I had declared a variable and set it's value in one one line. then I copied it later (accidentally keeping the type declaration for the variable - which stayed the same) and it refused to compile it

1:27 amalloy: yeah, it's annoying to declare a variable exactly once, when you'd like to copy the assignment line or something. to be fair though, it's not objecting to too-much-type-info

1:28 livingston: I passed a clj list out to my java program and tried to call println on it but all I get is: clojure.lang.LazySeq@4e63d25f how do I print the list trivially in java

1:28 I know I know, but it looks like that. I mean c'mon if you are going to make me spoon feed you types at least cut me some slack

1:29 amalloy: livingston: try new j.u.LinkedList(theLazySeq).toString() maybe?

1:29 i mean, even in clojure it's not "trivial" to print a lazy seq: ##(str (range 3))

1:29 sexpbot: ⟹ "clojure.lang.LazySeq@7480"

1:29 livingston: how does the repl do it?

1:30 amalloy: &(pr (range 3))

1:30 sexpbot: ⟹ (0 1 2)nil

1:31 livingston: ,(str (seq (range 3)))

1:31 clojurebot: "(0 1 2)"

1:31 livingston: &(str (seq (range 3)))

1:31 sexpbot: ⟹ "(0 1 2)"

1:32 livingston: ?

1:32 amalloy: ? ? ???

1:35 livingston: yep I cast it to ISeq and called .seq() on it and out it comes. Still doesn't seem elegant though.

1:37 mec: omg I think I finally understand monads. Now I must take the required sojourn into the forest to compose my own "what is a monad" tutorial

1:38 amalloy: congratulations, you now have permission to join the super-secret #clojure-awesome room

2:14 livingston: well good night and thanks everyone

2:48 Havvy: In Swank/Slime, how do you get it to tell you the line number the error was found on?

2:57 amalloy: Havvy: if it knows the line number, it tells you

2:59 zakwilson: Doing CPU-intensive things in Clojure on my laptop for long periods of time very reliably overheats my laptop unless I manually max-out the fan speed.

3:01 shachaf: function clj() { fanspeed max; clojure "$@"; fanspeed auto; }

3:01 Havvy: I haven't found the line number being shown yet in swank...usually shows it when there is no swank, but then I get classpath errors galore. :/

3:01 amalloy: zakwilson: are you objecting that, when you ask clojure to use your cpu, it uses your cpu?

3:02 shachaf: Clearly Clojure isn't CPU-efficient, which means the CPU heats up more than it does with other languages.

3:02 amalloy: Havvy: when there are exceptions during macroexpansion, iirc swank can't tell what line they're on

3:02 or, at any rate, C-c C-k can't; if you eval just a single form instead of the whole file, that sometimes helps

3:02 zakwilson: Well... no, but I don't think I've seen as much heat generated maxing out the CPU with other languages. This may be because I spend a lot more time maxing out the CPU with Clojure.

3:03 Havvy: I'd love stacktraces to remove all of the invokes though. Pure noise to me...

3:03 zakwilson: I AM complaining that my laptop doesn't ever set the fan to full-speed automatically, but any more on that would be off-topic.

3:04 Havvy: Anyways, is there a recursive version of map and apply so that when it finds a collection, is goes into the collection and does its operation on that?

3:04 amalloy: Havvy: clojure.walk/{pre,post}walk are probably what you want

3:04 or clojure.walk/walk if you need more fine-tuned operation

3:07 Havvy: Thanks.

3:23 seancorfield: map vs pmap question...

3:24 with map, operations only use 100% CPU on my quad core (therefore only one CPU) as i'd expect

3:24 with pmap, operations use 400% CPU (all four cores) as expected

3:24 however, pmap often takes LONGER to complete an operation than map

3:25 is the overhead on doing parallel operations really that high?

3:25 amalloy: seancorfield: split your task into fewer subtasks, each of which is larger

3:25 (yes)

3:25 seancorfield: my test case was a slow function that did 1,000,000 operations internally

3:25 and map that over 100 elements

3:26 map took about 15 seconds every time

3:26 pmap took 5 seconds the first time but then longer and longer on each subsequent time

3:26 amalloy: *eyebrow*

3:26 seancorfield: so i assume i need more heap...

3:26 but, seriously, that was not what i expected :)

3:27 amalloy: what do you mean, "every time"? every 1M operations, or every 1M*100 operation*partitions?

3:28 seancorfield: (dotimes [_ 10] (map expensive (repeat 100 1)))

3:28 that took 15 x 10 seconds

3:28 (map expensive (repeat 100 1)) takes 15 seconds

3:28 amalloy: okay

3:28 seancorfield: (pmap expensive (repeat 100 1)) takes 5 seconds on a clean jvm repl

3:29 but takes 10 seconds the second time, then 15 seconds, then 20 seconds

3:29 so (dotimes [_ 10] (pmap expensive (repeat 100 1))) takes a looooong time

3:29 instead of just 50 seconds

3:29 amalloy: seancorfield: are you sure you're actually forcing all the results?

3:29 try (comp doall pmap)

3:30 seancorfield: yeah, i'm actually doing a (reduce + ... ) on it, sorry

3:30 but (reduce + (map expensive (repeat 100 1))) was very consistent at around 15 seconds

3:30 amalloy: hm. "shouldn't" be any memory left over afaict

3:30 seancorfield: when i did it with pmap, it would always take about 5 seconds the first time

3:31 amalloy: $source pmap

3:31 sexpbot: pmap is http://is.gd/mVHNdG

3:31 seancorfield: and then longer and longer on subsequent times

3:32 anyways, i was mostly just curious how many people were using pmap and what they were seeing

3:32 amalloy: seancorfield: i used it once, last fall, when i was working on some computationally-intensive stuff

3:32 slowed me down when i used it naively, gave a moderate speedup when i used it sensibly

3:33 seancorfield: so maybe my problem is memory usage?

3:33 amalloy: maybe, but i can't see why the first run would be any different speed-wise

3:34 or memory-wise

3:35 seancorfield: i'll dig some more another day...

3:35 i wanted to use it as an example in a presentation but i can't get it to behave reliably :(

3:37 amalloy: while nobody's looking try (def pmap (constantly the-value-you-expect))

3:37 ought to be fast enough

3:38 seancorfield: here's my test code:

3:38 (defn expensive[n] (reduce + (repeat 1000000 n)))

3:38 (time (reduce + (map expensive (repeat 100 1))))

3:38 (time (reduce + (pmap expensive (repeat 100 1))))

3:39 and that gives expected results

3:39 but if you add dotimes around the reduce, the pmap slows down on subsequent evaluations

3:40 as written:

3:40 "Elapsed time: 25416.303 msecs"

3:40 "Elapsed time: 7165.128 msecs"

3:41 now change it to:

3:41 (defn expensive[n] (reduce + (repeat 1000000 n)))

3:41 (time (dotimes [_ 2] (reduce + (map expensive (repeat 100 1)))))

3:41 (time (dotimes [_ 2] (reduce + (pmap expensive (repeat 100 1)))))

3:42 and you get:

3:42 "Elapsed time: 49866.352 msecs"

3:42 "Elapsed time: 40540.13 msecs"

3:42 the map behavior is consistent: 2 x 25s is about 50s

3:42 but pmap goes from 7s to 40s... which means the second run takes 33s???

3:43 amalloy: seancorfield: or, if you're using the same repl still, both of those two are slower

3:44 seancorfield: well, yes... but really? why would pmap slow down when run multiple times?

3:44 each run was on a new repl... i'm running it with 4x now... just to see...

3:44 amalloy: i'd probably say ask on the mailing list. my best guess is that Thread objects are expensive?

3:45 seancorfield: lol... i will ask on the mailing list :)

3:45 but if thread objs are expensive, why is the single run so fast?

3:45 ok, 4x shows map at "Elapsed time: 97701.973 msecs"

3:45 which is exactly what is expected

3:46 still waiting for pmap run to finish :)

3:53 amalloy: $source future

3:53 sexpbot: future is http://is.gd/9xaEGV

3:54 amalloy: i wonder if the future objects somehow aren't being marked as "done"

3:57 seancorfield: my aging 2-core machine does not thank me for pasting your code

3:58 seancorfield: lol sorry :)

3:59 markoman: i need some design tips and advices for my forms app. particularly when im making questions types for forms, im not sure how should I code it in clojure

4:02 each question type has few different views they need to produce: creation of question, preview (html text mode), search view, report view (plain text mode), etc

4:03 amalloy: seancorfield: fwiw i see similar behavior, on 1.2.0

4:04 markoman: I could have question types core for generic behavior and using components, but where should I put each qtype, separate file each of them? own directory?

4:05 should I use clos/oo with this or just pure functions, maybe macros

4:06 I need to have flexible system, so that new question types are easily to be added later

4:07 no_mind: how do I fix error in line no. 0 "Exception in thread "main" java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to java.lang.String (webserver.clj:0)

4:07 "

4:09 amalloy: seancorfield: maybe the Thread objects just take some extra time to be GCd? if i do something else for ~5min between runs, the time goes down instead of up

4:12 Havvy: ,(.split "This is a test message FOR sure!" " ")

4:12 clojurebot: #<String[] [Ljava.lang.String;@82190a>

4:13 Havvy: How can I get it to show the actual string?

4:13 Err, array of strings...

4:14 amalloy: &(seq (.split "This is a test message FOR sure!" " "))

4:14 sexpbot: ⟹ ("This" "is" "a" "test" "message" "FOR" "sure!")

4:14 Havvy: Ah. That seems a bit annoying.

4:15 markoman: if I create a qtypes directory and put each qtype there in separate file, and say I have a set of questions on form each having type declared then on different parts of the application I should be able to call qtypes/single-select/generate-search-view-mode or something like that

4:16 amalloy: Havvy: feel free to change the source code of java.lang.String.toString

4:16 er, String[].toString

4:16 Havvy: Erm, that sounds like a scary prospect.

4:16 Creating a wrapper function is easier.

4:16 amalloy: indeed, i would characterize it as not possible

4:19 also, seq is already a wrapper function

4:19 and if you want clojure-friendly structures, use clojure functions instead of String.split

4:19 Havvy: Is there a clojure function that acts as String.split?

4:19 amalloy: &(doc clojure.string/split)

4:19 sexpbot: ⟹ "([s re] [s re limit]); Splits string on a regular expression. Optional argument limit is the maximum number of splits. Not lazy. Returns vector of the splits."

4:20 Havvy: Excellent.

4:20 amalloy: see also ##(doc re-seq)

4:20 sexpbot: ⟹ "([re s]); Returns a lazy sequence of successive matches of pattern in string, using java.util.regex.Matcher.find(), each such match processed with re-groups."

4:25 Havvy: I feel both newbish and noobish. :(

4:28 amalloy: re-seq is pretty sweet

4:29 if you have a reason to use regexes, anyway

4:30 markoman: im not sure if this makes any sense, but somethin glike this im thinking at the moment: (defn form-question-get [type mode & args] (call mode args (load "qtypes/{type}")))

4:31 Havvy: It is prettys sweet, and the example on cojuredocs even does what I want. :P

4:31 markoman: or actually load should be called before calling mode but anyway

4:37 or maybe I can (use 'forms.qtypes.{type}) is it bad practice to call (use) with same type over and over again? and when next type is called, it has similar function names than other types... maybe there is a name collision

4:38 seancorfield: amalloy: thanx for trying that code... the 5 min away time is very interesting

4:38 that suggests i just need more heap (and let java GC things in between)

4:38 amalloy: seancorfield: i think it may have been an illusion. just tried it after like 20 minutes and it took longer ;P

4:39 seancorfield: hahaha... ok... so it _is_ broken then? :)

4:39 amalloy: probably

4:39 who knows

4:39 seancorfield: btw, where in the world are you to be online at this time?

4:39 markoman: my next try would be something like this: (defn form-question-get [type mode & args] (use 'forms.qtypes/{type}) (mode args))

4:39 amalloy: san francisco, and stupid

4:39 seancorfield: oh, you're that local to me?

4:40 amalloy: you were at the clojure meetup, right?

4:40 seancorfield: i'm in castro valley

4:40 yeah

4:40 well, not at the april 7th one

4:40 i was at the CI Summit at linkedin

4:40 amalloy: i was at the last two

4:40 seancorfield: but yeah i've been at some of the bay area clojure meetups

4:41 bummed i missed clojureconj last year... but i _will_ be at it this year come hell or high water!

4:41 amalloy: yeah, same

4:42 seancorfield: i was in england for the march one

4:42 amalloy: at the time i was just picking up clojure, seemed a little too hardcore for me to go to the conj

4:42 seancorfield: i was in albuquerque :(

4:42 i had a cat show in ABQ then Adobe MAX in LA

4:43 this year i'm doing scala days, strange loop and clojure conj

4:43 amalloy: oh, i was trying to figure out where in england albequerque is

4:43 seancorfield: :D

4:43 i was speaking at a conference in scotland

4:43 amalloy: that's not in england either

4:43 * amalloy sees through your ruse

4:43 seancorfield: dallas, then scotland... home for a bit... then speaking in minneapolis...

4:44 i'll be bloody glad when my "conference season" is over!

4:44 amalloy: fortunately nobody thinks i'm interesting enough to hear me talk

4:45 seancorfield: i enjoy attending conferences more than speaking at them

4:46 Havvy: amalloy: That is not true. I would love to see a talk by you.

4:46 amalloy: Havvy: alas, i spend more time helping out in irc than doing actual things

4:47 Havvy: Alas, I know the feeling all too well.

4:48 Perchance, do you know how to get parenthesis to colorize in a default Clojurebox setup?

4:48 amalloy: clojurebox is...what, emacs?

4:48 Havvy: 23.1 of emacs, but yeah, emacs.

4:48 amalloy: $google emacs rainbow paren

4:48 sexpbot: First out of 181 results is: clojure - How do I get "rainbow parentheses" in emacs? - Stack ...

4:48 http://stackoverflow.com/questions/2413047/how-do-i-get-rainbow-parentheses-in-emacs

4:50 amalloy: anyway seancorfield, thanks for the reminder re time. unlike today, i have to be awake tomorrow morning

4:50 * amalloy is off to bed

4:50 Havvy: Night amalloy, and once again, thanks for the help.

4:50 amalloy: ta-ta Havvy

4:50 seancorfield: me too... gotta get up early and do litter boxes :(

5:47 Totramon: I'm having a problem with a "Too many arguments to def" exception when 40-something iterations into a loop

5:51 I wonder what could break after so many iterations?

5:52 and with such an exception msg

5:52 angerman: Totramon: what does your code look like?

5:55 Totramon: well, I'm implementing a genetic algorithm so it's a lot of code

5:55 jwr7: Is there a way to tell Clojure that I'm trying to aget something from a Java array of Strings (built using into-array? (and avoid reflection)

5:55 angerman: Totramon: what's the code arround the error?

5:56 Totramon: but well the outer loop is a loop - do - print - recur

5:56 jwr7: Basically, clojure complains about (aget arr i)

5:56 Totramon: I do not know what triggers it - the exception comes from repl

5:57 the most recent item on stack trace is clojure.lang.Compiler$DefExpr$Parser.parse (Compiler.java:415)

5:57 angerman: Totramon: don't look at the most recent, scan the stacktrace for parts that contain your file.

5:58 Totramon: there's nothing related to my code in it

5:58 hm, could there be a time limit to execution?

5:58 angerman: without you setting it? not that I know of.

6:01 Totramon: this is the output from the exception: http://pastie.org/1778250

6:03 angerman: that's all?

6:03 wow.

6:03 Totramon: yes

6:03 I'm using eclipse and counterclockwise btw if that's of any relevance

6:03 angerman: then this must be an issue with a def definition.

6:04 at some point you give (def ) more then 2 arguments.

6:04 maybe somewhere there is an (apply def )? or some other function composition.

6:05 Not that I'd understand why one would do that but, it could be a possibility.

6:05 Totramon: I don't think I use an explicit def anywhere

6:05 angerman: well, without code and how you invoke it, I'm lost here.

6:06 Totramon: ok. this really starts to look like a timelimit issue, because it fails exactly after 60 seconds every time

6:06 let's see...

6:06 angerman: I really don't think that the base repl inferes any timeout. Maybe it's counterclockwise or eclipse.

6:08 Totramon: ok I need to see if I can find such a setting somewhere

6:09 angerman: (or run it from command line ...)

6:09 or try something like (Thread/sleep 80*1000)

6:09 I still doubt it though.

6:13 Totramon: sleeping for 80 seconds didn't cause an exception

6:13 although, it didn't return a nil, either

6:39 oh, but of course... the stack trace was for a random exception

6:40 when the execution failed it didn't except at all

6:41 so actually the only error I get is "Expression failed <however I called it>"

6:42 found a relevant post now, too. thanks for help anyway

6:43 ccw does have an evaluation timeout of 1 minute

6:44 think I need to switch away from the RC version for now

7:21 cods: Is there a shortcut for (map (fn [o] (.myMethod o)) seq) ? I tried (map .myMethod seq) which is rejected.

7:22 well, I could do (map #(.myMethod %) seq)

7:22 which is short enough for me

8:22 fliebel: Where does the ants demo by Rich live? I believe someone updated it a bit?

8:24 Ah, maybe this one?

8:24 https://github.com/krukow/ants-demo

10:14 mec: how might i write a macro to turn (f a b) into (f 'a 'b)

10:16 Vinzent: something like `(quote ~arg) ?

10:17 TimMc: mec: (some-macro f a b) -> (f 'a 'b) is what you want?

10:18 mec: yes

10:18 TimMc: I'm not sure why you wouldn't just write (apply f '(a b))

10:18 mec: hmm indeed

10:19 $findfn '[x 5] 'x 5

10:19 sexpbot: [clojure.core/let clojure.core/loop clojure.core/when-let clojure.core/if-let]

10:19 mec: basically I dont want to have to do that

10:22 TimMc: but... (defmacro foo [f-expr & arg-syms] `(apply ~f-expr '(~@arg-syms)))

10:33 mec: well so much for that, doing it kills the ability to process regular functions

10:40 Is there a better way to do (juxt last butlast) that wont run the seq twice

10:45 TimMc: mec: Are you talking about lazy seqs, or about just needing to potentially walk through the whole thing?

10:46 mec: just walking it twice

10:46 TimMc: k

10:46 mec: right now i've just got #((juxt peek pop) (vec %))

10:46 TimMc: *nod*

11:12 mec: is there a version of keep that only keeps truthy values?

11:14 fliebel: mec: Isn't that what keep does?

11:14 mec: keeps false values also

11:14 TimMc: mec: filter identity :-P

11:15 just filter might be what you want

11:16 I guess the question is whether you want to keep the inputs or the outputs of your predicate.

11:16 mec: i guess i can just adjust the predicate to not return false

11:22 TimMc: $findfn identity '(nil false 1 true) '(1 true)

11:22 sexpbot: [clojure.core/filter]

11:23 mec: ,(str (doall (range 10)))

11:23 clojurebot: "clojure.lang.LazySeq@9ebadac6"

11:27 fliebel: &(str (seq (range 10)))

11:27 sexpbot: ⟹ "(0 1 2 3 4 5 6 7 8 9)"

11:49 fliebel: I need to merge multiple maps into one, but not just accumulate keys and the last wins, but more like git-style.

11:52 So say I have the original map, one map that has :x removed and one that has :y incremented. Now I want the result to be a map without :x and with the incremented :y.

11:52 TimMc: fliebel: The value are all numbers that are manipulated with addition?

11:53 fliebel: TimMc: No.

11:54 TimMc: How will you know that y was incremented as opposed to scaled?

11:54 fliebel: TimMc: I just care about changed, if both maps had :y changed, last-wins is okay.

11:54 -ish

11:55 I can think of something with clojure.set for changes, but I struggle with the deletions.

11:57 TimMc: (difference (set (keys a)) (set (keys b)))

12:00 fliebel: well… okay… hmmm… so that is one difference on the values for the changes and a revered one on the keys for the removals. And then stitch it back together.

12:00 *reversed

12:06 TimMc: fliebel: select-keys is your friend here

12:07 fliebel: TimMc: dissoc rather, I'd say. What comes out of the first diff can be conj'd into the original, and what comes of the second diff can be dissoc'd from that.

12:07 TimMc: Hmm, that works too.

12:17 fliebel: weee! user=> (octopus {:a 1 :b 2 :c 3 :d 4} {:a 2 :b 2 :d 4} {:a 1 :b 2 :c 3 :d 3}) {:a 2, :b 2, :d 3}

12:18 * fliebel finds it mildly annoying that his client turns some keywords into emoticons

12:18 fliebel: TimMc: ^

12:19 shachaf: fliebel: Instead of finding it mildly annoying, find it deeply infuriating. Then you'll care enough to fix it.

12:20 That's what I do, anyway.

12:21 TimMc: fliebel: nice

12:23 * fliebel has fliebel-utils living inside of his game engine by now

12:37 xkb: hi

12:37 I'm trying to fix this macro: https://gist.github.com/912494

12:37 where func should be the literal name of a function

12:38 I tried slicing and slice-unquote, but I think I'm missing something as I keep getting error messages

12:38 even on expand, esp. when I give something like Library/addArtist (a Java static method) as input parameter

12:38 any idea what I'm doing wrong?

12:39 Chousuke: xkb: you want (~func ~@args), most likely

12:40 xkb: so without apply?

12:40 Chousuke: (apply func ~args) expands to something like (apply func (arg1 arg2 arg3))

12:40 xkb: and that's what I want

12:40 Chousuke: no you don't :)

12:40 xkb: apply func to the arguments

12:40 Chousuke: you don't want to call the first arg as a function

12:40 with my form, you'll get (func arg1 arg2 arg3)

12:41 xkb: that's equal to (apply func (list arg1 arg2 arg3)) right?

12:41 __name__: Since when does Clojure have ~?

12:41 Chousuke: yes?

12:41 __name__: ~ is unquote

12:41 __name__: Ah.

12:43 Chousuke: xkb: note that (apply func (list arg1 arg2 arg3)) is not the same as (apply func (arg1 arg2 arg3)) :)

12:43 xkb: args is a list, due to & right?

12:43 so args actually is (list ....)? Or is that a wrong assumption?

12:44 Chousuke: hm

12:45 xkb: I think I'm missing something, can't really point out what though

12:45 Chousuke: ,((fn [& args] `[args ~args ~@args]) 'some 'args 'here)

12:45 clojurebot: [sandbox/args (some args here) some args here]

12:46 Chousuke: that's what gets used as the code

12:47 xkb: so I want the second, ~args I presume

12:47 as is in my code now

12:47 Chousuke: no

12:47 xkb: or without apply, the third

12:48 Chousuke: because then your code will end up being (apply func (arg1 arg2 ...))

12:48 and (arg1 arg2 ...) is a function call form

12:48 xkb: ahh yes

12:48 hmm 2 bad :) I had hoped to abuse the () form to append one extra argument

12:49 Chousuke: you can also do (apply func ~(cons `list args))

12:49 or (apply func ~(vec args))

12:49 xkb: ah yes

12:50 just delay the splice

12:52 anyway, this leads to the second problem.. if I try to expand the now changed macro, I get the error that the var func is not there..

12:52 called like this: (macroexpand-1 (with-error-handling (fn [a b] (Library/addArtist a b)) "OK" "FAIL" "Murk" (get-session)))

12:52 ah.. that anonymous

12:53 that's even

12:55 fliebel: Is there any way to kill a loop in lein without killing lein?

12:55 Chousuke: xkb: you need to unquote the func too.

12:55 xkb: Chousuke: thanks for the help!

13:02 oh, one more question. I expected a macroexpand on the with-error-handling macro to show the expanded macro, including the let. Instead it just shows the result of the computation, i.e. "OK". Why is that?

13:12 Chousuke: xkb: did you remember to quote the form that you macroexpand?

13:12 ,(macroexpand-1 '(fn [] test))

13:12 clojurebot: (fn* ([] test))

13:13 * xkb does CTRL-UP to check

13:14 xkb: ah I forgot the quote

13:14 thanks again

13:31 mec: fliebel: what did you end up using to merge your maps?

13:54 markoman: how can I do this kind of operation on clojure: (use 'lib.sublib."file")

13:55 the last part of the use is changing so practically if I have a library path on string format, how can I "use" it?

13:57 i could perhaps provide last part in format (use 'lib.sublib.:my-file) too

14:06 fliebel: markoman: Maybe (use ['lib (symbol "sublib")])

14:06 oh, wait, load-ile probably.

14:06 *load-file

14:07 markoman: there might be several loads for same file, does that matter?

14:08 fliebel: markoman: Multiple invocations of load-file will not return the previous result.

14:09 Maybe you could memoize it :)

14:10 markoman: ha, ive seen that word, memoize but dare not to find out, what it means

14:10 fliebel: markoman: It is really simple, it just stores arguments in a map, and when you run a function with the same argument, it looks up the return in that map rather than running the function again.

14:11 markoman: hmh, so far sounds like it could fit in this case

14:12 fliebel: markoman: Note that load-file doe not refer the loaded code, so it is not like use.

14:12 markoman: I try to design my library so, that naming convention on sublib files refer to symbols, so i dont need to create extra maps on app

14:13 see, I have this kind of situation: (defn form-question-type [type callee & args] (use '(str "magicforms.qtypes." type)) (callee args))

14:14 fliebel: markoman: w-wait, what am I conspiring in now? That sound quite bad, using use in a fn.

14:14 markoman: yes!

14:15 im experimenting it on repl and so far no idea, what I should do with it

14:15 fliebel: So you want to require stuff as you need it?

14:15 markoman: exactly, and I may need it zero, one or n times

14:16 fliebel: how much of these are there? Is it worth the trouble lazy-loading them?

14:16 You could also look into delay.

14:17 (def t (delay (require the.type))) @t @t will require it once.

14:18 markoman: im not sure about worth, but qtypes, its increasing library and files. all files has same functions like: create, list, show, etc

14:18 fliebel: ah, as long as you use require instead of use, that is not a problem/

14:19 then you write qtype/create

14:20 You can even alias these: (require '[blah.qtypes [foo :as f]]) (f/create)

14:51 markoman: fliebel: my connection broke, so did conversation in the middle...

14:54 raek: markoman: speaking of lazy code loading: http://groups.google.com/group/clojure-dev/browse_thread/thread/025821cbbfa47226#

15:03 markoman: raek: how does that affect to use, require?

15:04 raek: I merely know that this exists, nothing more... :)

15:05 it struck me as a potential solution to "So you want to require stuff as you need it?"

15:07 markoman: so, why do you need to dynamically load code?

15:07 markoman: hmh... you are right, im not sure how i could use it here at the moment, but I can see possibility. only thing is, that i dont want to do duplicate work for mapping things

15:07 let me try to explain that

15:08 raek: ...or why is does not a :require in the ns do the trick in your case?

15:08 markoman: (defn form-question-type [type callee & args] (require '(str "magicforms.qtypes." type)) (callee args))

15:09 it probably does, i was using use as a first sketch, but guessed it may cause name pollution or other problems

15:10 i dont know exact difference between use and require. but i have a library or question types I want to load "dynamically". 0, 1 or n times depending how many questions are that type

15:10 or = of

15:11 raek: I think there are simpler ways of representing the question types than namespaces

15:12 choffstein: Hey all. I have a quick question. I keep getting an arity error, but I can't figure out why.

15:12 I've used let to define a function (e.g. (let [f (fn [a b c] ...)])). When I try to pass it three arguments, though, I am told I am only passing it two ... which is horrendously frustrating.

15:13 raek: markoman: this cannot work, since before a function is compiled, all vars it uses (e.g. fns in other namespaces) must be loaded

15:13 markoman: i was thinking clos / oo approach too, but here the main criteria is, that librarry is evolving and growing, and each question type has functions lie: create-get, list-get, show-get, validate-get, search-get and so on

15:13 choffstein: Any ideas why this may be happening?

15:13 raek: well, technincally, the vars need to exist

15:14 choffstein: I don't see anything strange in that snippet there

15:14 trptcolin: choffstein: what raek said. what's the caller look like?

15:15 raek: markoman: is there any reason you can't store everything in ordinary clojure data structures?

15:15 markoman: raek, but if there are no vars, just function on each qtype file?

15:15 raek: vars in namespaces is what "names" functions...

15:16 when you have (defn foo [] (bar)), bar is a reference to the bar var, not the function it holds

15:16 choffstein: trptcolin: like (f 1 2 3)

15:16 markoman: raek, probably not :) this is just the way, I have made it on other language, but they werent compile languages, python and php namely so I could just load what I needed

15:16 choffstein: trptcolin: I'll gist it

15:16 raek: yeah, in python, a module is basically just an object with attribues

15:16 in clojure, that is not exactly the case

15:17 so clojure is more "compily" in this aspect...

15:17 trptcolin: choffstein: cool

15:18 markoman: i see. but i still would like to have all types easy and separate, so I can add, modify them later if needed. think of adding new type by defining mandatory functions

15:18 raek: I would recomment having a global var holding some data structure that contains that stuff

15:19 choffstein: trptcolin: https://gist.github.com/912628

15:19 trptcolin: first-date, (get (:data file-data) first-date), and initial-index-value all evaluate correctly.

15:19 trptcolin: :) haha, "..." indeed

15:19 markoman: im afraid it can get complicated... well maybe not a problem. but I can have dozens of question types, simple and custom qtypes. and each of them needs to have same functionality that the form building function can call

15:20 raek: you could have a map like {:foo {:create (fn ...), :list (fn ...), :show (fn ...), :validate (fn ...), :search (fn ...)}, :bar ...}

15:20 choffstein: And the error is: Wrong number of args (2) passed to: core$construct-index-by-pct$shares-on-date

15:20 devn: clojure project! https://github.com/codahale/metrics

15:20 scala -> clojure

15:20 choffstein: trptcolin: actually, hold on. the whole file is up on github. let me find it.

15:20 raek: remember that it is possible to store functions in data structures too :)

15:21 choffstein: trptcolin: https://github.com/newfoundresearch/construct-index/blob/master/src/construct_index/core.clj -- in construct-index-by-pct

15:21 raek: markoman: I don't know much about the design problems you're facing, but I can tell you this: representing domain data as vars in a namespace will just make it even more complicated

15:21 choffstein: trptcolin: don't be too harsh on the code -- it is my first run through on it. just getting it to work before refactoring

15:21 markoman: yeah, I saw that once on some code :) I guess that could work. and you think putting it on separate files is not good? say other developers want to add new type, they could just put new file on system and thats it?

15:22 trptcolin: i won't be :) i'm just thinking it'd be easier to debug with functions split out to remove dependencies

15:23 choffstein: trptcolin: I was trying to keep them in the let because they relied on the values above -- and the inner functions are different within construct-index-by-pct and construct-index-by-shares

15:23 raek: markoman: perhaps you can have an namespace that acts as an api with functions for adding qusetion types?

15:23 markoman: I have a feeling that what you do is similar to how 'derive' works in clojure

15:24 it allows libraries to add stuff to a global hierarchy

15:24 markoman: probably, i need to check google

15:26 raek: it could be as easy as having (def types {}) (defn register-type [name stuff] (alter-var-root #'types assoc name stuff))

15:27 or if things change at runtime: (def types (atom {})) (defn register-type [name stuff] (swap! types assoc name stuff))

15:27 trptcolin: choffstein: i wonder about this line: "(reduce #(+ %1 (Double/parseDouble %1)) 0 data-row)"

15:27 ,(reduce #(+ %1 %1) 0 [1 2 3 4 5])

15:27 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (2) passed to: sandbox$eval5396$fn

15:28 trptcolin: you probably want a %2 in there somewhere

15:28 choffstein: ahhhh, yes

15:29 you, sir, are a genius!

15:29 trptcolin: it'd be nice for that error message to give some clue that the fn in question is anonymous *under* the fn it gives...

15:30 but yeah, generally if you can find a way to break that up it'll be easier to verify all your behavior is what you intend :)

15:30 raek: markoman: if you have something like that, other namespaces can add types. splitting code into managable chunks is always a good idea...

15:31 markoman: i dont think I let types change at runtime, when new types comes in, I need to deploy anyway. its just for code management

15:32 trptcolin: devn: that looks pretty tasty

15:32 markoman: I can think now for using global map as you suggested, maybe combines to that each namespace adds new section on map, or the other register type way...

15:36 oraek: but you still mean I need to register all question types on same types map?

15:37 raek: markoman: well, you could have multiple maps. but the point is that the number of vars holding maps should not vary with the number of namespaces that needs to add information

15:38 maybe it helps to think of vars in namespaces to be static

15:40 markoman: ok, well now, because I need to add all qtypes on map and they all are in qtypes directory, is there a way to read directory and simply add all that is found by their file / namespace name?

15:41 raek: also, will the namespaces only contian data (and no code)?

15:41 if so, it might simply be better to load data from some files

15:41 markoman: so I could escape from duplicate writing because all qtype filenames are already qtypes

15:42 well because data structure can hold functions, it would be only data :)

15:44 raek: its probably possible to scan a directory on the CLASSPATH for .clj files and load them

15:44 but as a start, it is probably easier to just list them in the :require form in some namespace

15:45 markoman: ok and sorry, I have no good example to show, because its all immature for now, maybe I try with these tips and get back with questions

15:46 raek: I think it's easiest to start with functions that use the data first, and build a question module system on top of that later

15:57 markoman: raek: btw why you use alter-var-root and not just (types assoc name stuff) ?

15:59 mreynolds: newb question : I'm trying to run a multi-module program I've written. I can get the main method up, but I'm confused about why sometimes I get CNFE for some classes, but not others. Am I supposed to be using gen-class?

16:00 raek: markoman: 'types' contains a map, and calling it as a function won't do what you think

16:01 (m key) (m key default) are the same as (get m key) and (get m key default)

16:01 mreynolds: A better way of saying this is, what "I need to use methods from other modules" keyword am I supposed to use when I'm writing an all-clojure program? I've been using a mix of "use" (for utility methods) and require for modules

16:02 trptcolin: mreynolds: use and require are generally for vars - if you're using defrecord/deftype you'll need import as well

16:02 raek: mreynolds: are we talking about methods and classes (java land) or functions and namespaces (clojure land)?

16:03 mreynolds: trptcolin: Thanks, that's what I just realized wasn't working. I need import because it's creating real Java classes?

16:03 trptcolin: yep

16:03 mreynolds: raek: functions, sorry. Java trained brain. This is all clojure code (which sometimes uses java), but the problem so far is all in my clojure only code.

16:04 raek: mreynolds: you should not get CNFE for clojure-only stuff

16:05 import is only for shortening the name of java classes (and is not used for namespaces)

16:05 mreynolds: raek: Hmm

16:05 raek: so, I assume you files looks something like this:

16:06 in file src/a/foo.clj: (ns a.foo) (defn hello ...)

16:06 mreynolds: So, here's the setup. I have a defrecord (ns com.example.x.y.z) (defrecord Location [a b c]). Then I have (ns com.example.d.e.f (:import com.examples.x.y.z Location))

16:07 raek: in file src/a/bar.clj: (ns a.bar (:use [a.foo :only [hello]])) (def blah [] (hello))

16:07 mreynolds: I'm double-checking for typos, but the import seems to be not working

16:07 raek: ah, I see

16:07 trptcolin: (:import [com.examples.x.y.z Location])

16:07 (needs the vector)

16:07 raek: you need to both require the namespace that defines the record and then import the class

16:07 mreynolds: trptcolin: That's it. Thanks. I need to create a cheat sheet for that.

16:07 import doesn't do both, eh?

16:07 Weird

16:08 Or, weird to my yet-to-be-trained-brain

16:08 raek: sorry for misleading you. you can indeed get CNFE this way...

16:08 this is a known problem

16:08 mreynolds: raek: no worries

16:08 trptcolin: yeah, records are a bit fussy wrt nses...

16:08 mreynolds: raek: I've dealt with Java for so long, this actually seems happy and warm and soft

16:09 I think I get the underlying issue, mainly that records are official objects, get created as such, and this need to be imported

16:09 Rather than "used"

16:09 raek: I common workaround for this is to let the user use a constructor function, instead of the record class constructor

16:10 mreynolds: raek: Yeah, I read that in the Joy of Clojure (I think), and plan to switch to that now

16:10 raek: http://dev.clojure.org/display/design/defrecord+improvements

16:11 mreynolds: raek: Thanks!

16:12 raek: (import only affects how symbols are resolved the namespace, and doesn't do any loading)

16:13 *in the

16:14 mreynolds: Right, basically via java lookup, directly in the NS, or via a lookup? This is one the murkier parts of clojure that my brain has trouble with, but I think I have it down enough to get a working app up

16:15 import :: java, use :: directly in ns, require :: referenced via keyword

16:15 ?

16:18 raek: (import 'javax.swing.JFrame) only causes JFrame symbols to resolve into javax.swing.JFrame in the current namespace

16:18 require and use on the namespace foo.bar causes the file foo/bar.clj to be evaluated if it hasn't been already

16:19 mreynolds: raek: Tangential question - Why use 'javax.swing.JFrame vs (javax.swing JFrame)?

16:19 ah, good to know about evaluation

16:19 I have read this stuff, but it's not sticking immediately, sorry for the newb questions

16:19 trptcolin: those are equivalent, but you might want (javax.swing JFrame Icon Action)

16:19 raek: '(javax.swing JFrame) is easy to change into '(javax.swing JFrame JLabel) :)

16:20 trptcolin: word

16:20 mreynolds: you probably just covered everything, but i have a blog that goes into some detail about these: http://blog.8thlight.com/articles/2010/12/6/clojure-libs-and-namespaces-require-use-import-and-ns

16:20 raek: use, but not require, will cause all the vars in that namespace to be available without a complete namespace prefix

16:20 mreynolds: trptcolin: I'll go read that

16:22 * raek saves that for future "pointing-to"

16:23 mreynolds: Oh, one other rub. I'm doing the "Load a script" incantation from ( http://clojure.org/repl_and_main ), is there a way to have main start a repl after executing my script? I tried "-r" but that just starts a repl, without loading my script?

16:24 I thought about just using a script with a hardcoded -e that loads my program, but haven't figured out if that would work yet

16:25 choffstein: Can I check if a Java Date is in a collection using contains?

16:25 It doesn't seem to be working for me and I can't figure out why

16:25 trptcolin: what kind of collection? :)

16:25 raek: clojure is not really made for scripting, so something like 1) start a repl 2) require start namespace 3) invoke (start.namespace/-main) is probably the easiest

16:26 choffstein: list

16:26 raek: choffstein: 'contains?' should be read 'has-key?'

16:26 trptcolin: contains? may not work as you expect for things other than sets & maps

16:26 clojurebot: Titim gan éirí ort.

16:26 choffstein: ahhhh

16:26 well, that explains it then!

16:27 is there a way to check if a list contains an element?

16:27 raek: to do a linear seatch for the element, use (some #{elemenent} coll)

16:27 but if you search for elements in the collection often, you might want to consider to use a set as the datastructure

16:28 since those are specialized in checking membership

16:28 choffstein: raek: yeah, a set would be much better

16:48 markoman: so i got this far: (:search (qtypes :single-select) "args1") it returns the function, but how do I actually execute it?

16:48 brehaut: ((:foo {:foo inc}) 1)

16:48 ,((:foo {:foo inc}) 1)

16:48 clojurebot: 2

16:49 markoman: cool, thanks

17:17 (defn element ([name] (element name nil)) ([name value] (element name value nil)) ([name value id] (element name value id nil)) ([name value id options] ,,, ))

17:17 is there some smarter way to do this, because I see its going to repeat again and again for different elements

17:28 seancorfield: markoman: maybe use named arguments with defaults instead?

17:29 Derander: is there a way to pass -Xms and -Xmx args through lein swank to increase heap size?

17:29 markoman: this is the way i though it is done in clojure :)

17:32 seancorfield: (defn element [name & { :keys [value id options] :or {value nil id nil options nil}}] (println name value id options))

17:32 (element "n" :value "v" :id "i" :options "o")

17:32 (element "n")

17:32 (element "n" :id "i")

17:33 raek: markoman: it is the only way to do it if you want it to only allow the arities you specify

17:33 seancorfield: pity you can't have a [name value id options] :or [nil nil nil nil] sort of destructuring...

17:34 raek: someone should make a macro for this...

17:34 markoman: i think I once saw related macro...

17:37 raek: (defn-default element [name ? value nil, id nil, options nil] ..) -> (defn element ([name] (element name nil nil nil)) ([name value] (element name value nil nil)) ...)

17:51 markoman: clojure.contrib.def/defnk could work?

17:53 seancorfield: defnk would provide syntactic sugar vs what i was suggesting, yes

17:58 markoman: alright, its time to sleep. thanks sean and raek for your insights

17:58 seancorfield: here's a version with optional positional args:

17:58 (defn element [name & xs] (let [args (args-to-map [:value :id :options] xs [nil nil nil])] (println name (:value args) (:id args) (:options args))))

17:58 (defn args-to-map [ names values defaults ] (apply hash-map (apply concat (map list names (make-default values defaults)))))

17:59 (defn make-default [values defaults] (if values (cons (first values) (make-default (next values) (next defaults))) defaults))

17:59 i'm sure there's much cleaner versions of those two helper functions

17:59 markoman: so its much talked about syntactic sugar, but what is syntactic salt then?

17:59 seancorfield: but a little macro magic could make it much cleaner

18:02 markoman: i see, i need to copy that for tomorrow and see how things work

18:46 mec: does destructuring change the collection type?

18:47 brehaut: mec: if you use a vector to destructure a vector and use a remainder form, then you get the remainder as a seq if thats what you mean

18:47 mec: otherwise you get the elements as they are in the collection

18:48 mec: ah, so i shouldnt destructure a queue

18:48 brehaut: mec and the collection itself doesnt change due to the destructuring

18:48 mec: it depends/

18:49 mec: in particular it depends on what sort of queue you are using

18:49 mec: PersistentQueue

18:49 brehaut: mec then i cant see it being a problem

18:50 mec: unless you want to just treat the remainder as a queue

18:50 mec: if I do (let [[x & rqueue] queue] ...) if it changes rqueue from a PersistentQueue then i wont be able to keep using it

18:50 brehaut: rqueue is never a persistentqueue

18:51 ,(destructure '[[x & r] [1 2 3]])

18:51 clojurebot: [vec__5404 [1 2 3] x (clojure.core/nth vec__5404 0 nil) r (clojure.core/nthnext vec__5404 1)]

18:51 brehaut: mec: you can see that r is bound to the result of nthnext

18:52 mec: ah ok

19:24 how might I conj 2 items onto a collection so that if either is nil that one wont be added

19:25 (into coll (filter identity [x y])) i guess but i just hate filter identity for some reason

19:32 mreynolds: I have a "plugin" framework I'm trying to build, where I have an agent keeping track of the functions that I want to "plugin". I have an event and I want to have all the plugin functions run, passing in this event. I'm missing something obvious because -> isn't doing what I expect (-> event (registered-plugins)) where (registered-plugins [] @agent-name)

19:37 mec: registered-plugins is a vector of agents?

19:37 mreynolds: mec: Set, actually

19:37 mec: Er, it's a set, held by an agent

19:38 mec: Er, wow, sorry. Vector held by an agent.

19:38 mec: (-> event (registered-plugins)) is just (registered-plugins event) but if registered-plugins is an agent you would need (@registered-plugins event)

19:39 mreynolds: I'm trying map, and everything seems to be running... it's just not executing those functions. I have a sneaking suspicion it's being lazy

19:39 mec: oh, neat

19:39 mec: Lemme try that

19:41 mec: I must be doing something dumb because that seems to be treating event as an index into the vector

19:41 mec: the contents of the vector are functions, if that helps

19:42 mec: oh and you want to run each function with event as arg?

19:42 mreynolds: yeah, sorry

19:42 mec: Brain is getting a bit worn

19:43 mec: ((apply juxt @registered-plugins) event)

19:43 mreynolds: mec: It feels like a pretty simple problem, but I have too many levels of indirection I'm not familiar with yet.

19:43 I'll try that

19:45 brehaut: mec: perhap you would prefer (remove nil? col) ?

19:47 mreynolds: (map #(%1 event) @plugins-agent) ?

19:47 mec: brehaut: I thought about that one, but that juxt just looks beautiful

19:49 brehaut: mec: im not sold on it for this usage

19:49 mreynolds: mec: That worked

19:49 mec: he mentioned map being lazy so it saves an extra (doall)

19:49 mreynolds: brehaut: Almost worked, but didn't print... I think it's a lazy issue between the two styles?

19:50 mec: mreynolds: for the map you gotta wrap it in a (doall (map ..)) for side effects

19:50 mreynolds: mec: Yup

19:50 thanks

19:50 Is there an easy way to tell that a chain is lazy and won't be called?

19:50 I mean, normally, that's awesome

19:51 For debugging purposes, with println, it's not so awesome

19:51 brehaut: mreynolds: know what your data is?

19:52 mreynolds: brehaut: Yes, events coming in from a client. Normally, each function would be called an will act upon that event, possibly returning other events to be sent back to the client. Not in this case, though.

19:52 Did I answer your question?

19:52 brehaut: mreynolds: nope; i mean that you need to know what your data is to know when it needs to be realized etc

19:53 mreynolds: brehaut: Sorry, not sure what "realized" means in that sense

19:53 brehaut: mreynolds: a lazy computation is only evaluated when it is realized

19:53 realization is the process of taking that thunk and replacing it with the computed result

19:53 mec: pretty much if you use any of the core collection functions, its going to be lazy

19:53 mreynolds: brehaut: Gotcha. I think I need a way to force that for debugging purposes and I'm not sure how to do that yet.

19:54 brehaut: mec not true, only the sequence functions

19:54 mreynolds: dorun is the answer

19:54 mreynolds: you shouldnt be putting side effecting code into a sequence anyway

19:56 (apply the same caveats you would to any other blanket statement to that one too)

19:56 mreynolds: brehaut: Right, I'm pretty sure I'm not thinking about this correctly yet. I have a stream of client data and I want to segregate the areas of concern and allow different modules to respond to different client requests

19:56 I figured building a "hub" to distribute the events to incoming modules would allow them to process the event and respond, if needed. I like that it's lazy in that case.

19:56 brehaut: mreynolds: first question then: do you care about the result of the pluggin?

19:57 mreynolds: brehaut: At this point, I don't

19:57 brehaut: I'm having a hard time thinking of a case where I would

19:57 brehaut: then go with no until you discover a case

19:57 mec: (doseq [f @registered-plugins] (f event))

19:57 brehaut: i would suggest using a doseq

19:57 just like that :)

19:57 mreynolds: alright, I'lll try that :)

19:57 mec: lol

19:58 brehaut: simply because its explicit that it side effecting

19:58 mreynolds: I was avoiding it because of the "side-effects" in the docs, but that's actually exactly what I want

19:58 heh

19:58 Thanks for helping me think about that differently, guys

19:58 I'll go re-work a bit

19:58 brehaut: no worries

19:58 mreynolds: side effects are fine if the program is clear about their scope and effect

19:59 mreynolds: brehaut: Yeah, that's the part I need to figure out next. I'm trying to figure out my audience so I can try and determine how much I should/shouldn't manage for them from a data and session standpoint

19:59 brehaut: mreynolds: im curious about why you have a non-pure plugin system though; what are youy building?

19:59 mreynolds: brehaut: It's a toy minecraft server, mostly so I can learn clojure more fully

20:00 brehaut: mreynolds: what are the plugins responsible for?

20:00 mreynolds: brehaut: At work, I'll be using clojure and ring to build simple REST servers so others can use them as prototypes.

20:01 brehaut: mreynolds: that should be really straight forward (ring + rest)

20:01 mreynolds: brehaut: Plugins are responsible for various tasks like : *returning portions of the world when clients enter an area, * managing inventory, * etc

20:01 brehaut: Yeah, actually way easier than this problem I have at home

20:01 brehaut: yes

20:01 if you are doing simple json stuff its almost just falls out by itself

20:02 mreynolds: brehaut: Yeah, I will be. But I also know, eventually, I'll have to show some java interop stuff with existing badly written code, so I figured I'd stretch myself a bit and try building something larger

20:02 brehaut: I'm, effectively, leading several teams out of J2EE/RMI driven architecture and into something else. They'll all be using Java due to comfort with the language.

20:03 * brehaut feels ill at the mention of RMI

20:03 mreynolds: brehaut: Part of the reason for the plugin bit is I may try and build them a sandbox framework to deploy java code into and it would probably look similar

20:03 brehaut: Yeah, the existing mess is ... messy

20:03 brehaut: mreynolds: why did you chooses an agent for your plugins ?

20:03 rather than say an atom

20:04 mreynolds: brehaut: No particular reason. I liked the async portion of agents for management of the plugins.

20:05 brehaut: I'm still learning which ones are best. My goal is to not allow the plugins to interrupt each in a big way, when possible.

20:05 brehaut: they one interrupt each other in either case

20:05 mreynolds: Eventually I plan to externalize the events to allow for choosing between in-process and out-of-process messsaging

20:06 brehaut: err they wont

20:06 mreynolds: brehaut: It's more about behaving really poorly (blowing the stack, heap, etc). The examples I have are simple now, but have similar constraints

20:06 brehaut: For the home server, the world can be mismanaged and eat a ton of memory, etc

20:07 brehaut: But you're right, from a processing standpoint, it won't matter

20:07 My primary concern, at work, will be programmers making bad engineering decisions and needing to contain those

20:09 brehaut: mreynolds: i prefer education to api constraints to solve that problem ;)

20:10 mreynolds: brehaut: That's step 2. First step is proving that they're making bad decisions without allowing them to sink the app :)

20:10 I'm new and I don't have a ton of buy-in for the style I'm proposing

20:11 I could override and be a dick about it, but I'm trying to give people a chance to try things out under less pressure, but remove the immediate risk they have

20:11 brehaut: mreynolds: in my opinion you dont want to straightjacket them

20:11 let them make their own mistakes and learn from it

20:11 mreynolds: brehaut: In the long run, sure. In the short term, the company doesn't have the ability to absorb too many big mistakes, I think :/

20:12 brehaut: They are good people, mostly smart, but have been doing the same thing for 10 years and haven't upgraded skills in that timeframe

20:13 brehaut: There's a pretty large set of basic skills that they haven't picked up over the years. Even reading JCIP is a good start.

20:13 Anyway, not to rant too much about work :) I appreciate the help.

20:15 crowbar: Is there a special command for starting cake? If I initiate it in teh project root it just says jvm is taking a long time

20:16 znutar_: is using java IO classes the idiomatic way to read things from stdin?

20:16 brehaut: znutar_: yes; clojure.java.io provides utilities to do so

20:17 znutar_: see also http://clojuredocs.org/quickref/Clojure%20Core

20:18 mec: znutar_: on the off chance that you're using emacs, reading from slime is buggy

20:25 crowbar: Is it possible to install clojureql with lein? I'm running into issues where i'm missing an artifact. org.apache.maven:super-pom.jar?

20:26 brehaut: crowbar: i have in the past

20:27 crowbar: http://clojars.org/clojureql

20:27 crowbar: I tried that. Looks like I might have a different problem though.

20:28 brehaut: running the latest lein?

20:29 crowbar: Leiningen 1.5.0 on Java 1.6.0_24 Java HotSpot(TM) 64-Bit Server VM

20:30 brehaut: im out of ideas then sorry

20:30 crowbar: thanks for the help. do I need a clojars plugin? I've ready so many blogs and tutorials trying to learn compojure this weekend everything bled together.

20:31 brehaut: nope clojars should just work via maven plumbing

20:31 crowbar: did you post about this on HN today?

20:31 crowbar: maybe :)

20:31 small world.

20:31 brehaut: not really :P

20:32 http://news.ycombinator.com/item?id=2430037 im presuming?

20:32 i didnt know what you meant by over-hyped development style

20:32 crowbar: heh. yep. I've pretty much had a horrible time at every step in the process.

20:33 brehaut: i found that quite surprising; i have had basicly no trouble getting runnign with ring etc

20:33 crowbar: ring actually was easy.

20:33 brehaut: thats part of the magic of it :)

20:33 ive not really used compojure myself

20:34 so i dont know if thats been the source of your issues

20:35 crowbar: swank has been terrible. half the tutorials for it wanted me to run it in emacs, the other half say lein is what I should use. all the ring stuff is pretty straight forward. But then compojure stuff is spread over so many versions that it doesn't really help. I'm spoiled by the django tutorial.

20:35 brehaut: crowbar may i suggest hopping on #clojureql - you might get help with the specifics there if its not a lein issue

20:35 crowbar: ok i have completely avoided swank

20:36 crowbar: but from what i understand you should ignore every tutorial in the wild and follow the instructions in the README.

20:36 crowbar: the django tutorial is pretty good

20:37 crowbar: I think I'm having just a general lein issue.

20:37 brehaut: crowbar: on the other hand, even from day one django was an order of magnitude and some larger than compojure. you really can learn a lot of how compojure works just by reading the source (theres about 200 lines)

20:37 znutar_: brehaut: mec: thanks!

20:40 Is the super-pom.jar message something that pops up whenever lein can't satisfy deps? I got that earlier when I installed lein as root using macports and things were failing due to permissions issues

20:41 dnolen: crowbar: personally I prefer plain ring w/ moustache for routing. hiccup for simple templating things, enlive for more serious templating. that said there's nothing like Django yet, but Django has it's own pluses and minuses.

20:43 brehaut: enlive is a reason to persevere with clojure for web all by itself

20:48 Raynes: brehaut: Man, I'm writing some straight HTML for the first time in forever. :o

20:48 brehaut: Raynes: i do that all the time :P my latest blog post is 4500 words all manually marked up :P

20:49 Raynes: My blog posts are usually only slightly marked up.

20:49 brehaut: i often use markdown, but this one has diagrams

20:49 and i did them with html and css

21:13 jweiss: is there really no way to conditionally add a key to a map literal? something like { :a :b :c :d (if blah (:d :e))} (i know that's not it, but just to give the idea of what i want)

21:14 syntax quote and unquote splicing almost works

21:14 but it doesn't

21:14 ,`{~@[:a b:]}

21:14 clojurebot: Invalid token: b:

21:14 jweiss: ,`{~@[:a :b]}

21:14 clojurebot: 1

21:17 mec: wow apparently lazy-seq binds recur :x

21:17 dnolen: jweiss: don't think that's possible, but I also don't see much benefit.

21:17 mec: ?

21:17 mec: ,(lazy-seq (recur))

21:18 clojurebot: Execution Timed Out

21:18 dnolen: ,(recur)

21:18 clojurebot: Execution Timed Out

21:18 dnolen: mec: nothing to do w/ lazy-seq

21:19 mec: in my code i've got (fn blah [x] (lazy-seq ... (recur y))) and it says recur expects no args

21:23 gtrak: there might be a loop in the ...?

21:23 .(recor)

21:24 .(recur)

21:26 dnolen: mec: recur on lazy-seq doesn't make sense. lazy-seq computations are more general than recur.

21:27 (fn blah [x] (lazy-seq ... (blah y)))

21:27 mec: ^ is what you want.

21:30 mec: i have to do some extra computation inbetween the lazy-seq bindings

21:31 dnolen: mec: ? and what stops you from doing that?

21:37 mec: thats what the recur was for

21:38 hang on i'll gist this

21:39 dnolen: mec: you can't use recur inside lazy-seq, there's no place to recur to.

21:40 mec: https://gist.github.com/912946

21:41 brehaut: mec: yikes!

21:42 mec: lol, i think i can just nuke the lazyness anyway since almost all of the calculation is done by the time the seq is created

21:43 brehaut: mec :when (identiy new-pos) is the same as :when new-post

21:44 mec: ah right, just blindly changed that from (filter identity)

21:44 brehaut: mec: well also new-pos is always truthy i think; only nil and false are falsy

21:44 mec: it could be nil if x or y are <= 0

21:45 brehaut: ,(boolean [])

21:45 clojurebot: true

21:45 dnolen: mec: your code works fine for me.

21:45 mec: ya i added the loop, before it was just the fn

21:46 brehaut: ,(boolean [(when (pos? -1) [1]) (when (pos? -1) [-1])])

21:46 clojurebot: true

21:46 brehaut: ((juxt identity boolean) [(when (pos? -1) [1]) (when (pos? -1) [-1])])

21:46 ,((juxt identity boolean) [(when (pos? -1) [1]) (when (pos? -1) [-1])])

21:46 clojurebot: [[nil nil] true]

21:46 mec: dont forget the for pulls the vector apart

21:47 brehaut: ah true

21:57 mec: i feel this is overly complicated in general

22:07 devn: g'day all

22:18 crowbar: ARRRggg. Just realized the issue was that I have to disable ipv6 for java to reach the network.

22:18 because I removed openjdk and install sun jdk by recommendation of some stupid blog that openjdk breaks clojure.

22:18 Anyway, lein and clojars was not the issue.

22:23 amalloy: mec: you definitely can't recur across the boundary of a lazy-seq. it doesn't make sense

22:24 the good news is, there's not really any reason to want to do so

22:24 mec: i know, i just forgot to add in a loop

22:26 amalloy: mec: incidentally, it looks like the pattern you're using in routes* is the same as the one i built a little abstraction for at https://github.com/amalloy/amalloy-utils/blob/master/src/amalloy/utils/seq.clj#L32

22:26 i wonder whether having a loop/recur inside a lazy-loop/lazy-recur makes things less readable

22:27 mec: its that or get rid of the lazy and loop, but have to carry around a results vector

22:28 amalloy: mec: not really. you could drop the inner loop entirely

22:29 (if (= 0 x y) (cons result-level (routes* queue-left)) (routes* (into queue-left ...)))

22:30 since the loop target of your recur is at exactly the same place as the lazy-seq recur target; just don't cons anything if you want to keep going without adding a new result

22:33 mec: oh? i can do this immediatly in my code?

22:34 amalloy: indeed, the snippet i pasted should "just work"

22:34 mec: wow, so the lazy-seq just keeps calling that until it gets a value? no chance of a stack overflow?

22:34 amalloy: mec: that's the magic of lazy seqs

22:35 it's effectively using the caller's stack frame as a trampoline

22:35 mec: huh never knew that, i thought it always had to return a value

22:36 amalloy: &((fn make-zero [x] (if (zero? x) [0] (make-zero (dec x)))) 10000)

22:36 sexpbot: java.lang.StackOverflowError

22:36 amalloy: hm

22:36 hah forgot lazy-seq: ##((fn make-zero [x] (lazy-seq (if (zero? x) [0] (make-zero (dec x))))) 10000)

22:36 sexpbot: ⟹ (0)

22:36 amalloy: an apt demonstration of the fact that it works, i guess

22:36 mec: very true

22:37 so how does this work?

22:37 amalloy: mec: same way any lazy-seq works. it wraps up the body of the lazy-seq macro in a thunk, and returns that thunk immediately

22:37 the caller sees it, notes that it's a lazy-seq, and asks it to force itself

22:38 a thunk is immediately returned, which is forced...

22:38 glossing over details there, but that's the general flow

22:43 mec: theres actually a couple places I can apply that little bit of knowledge to

22:46 they did the exact same thing in Joy of Clojure ;p i wonder if they didnt know about it or just tired to keep things simple

22:47 amalloy: mec: loop/recur is surely faster. avoids creating and destroying stack frames

22:48 mec: ah i see

22:51 looks like they are near identical in speed

22:53 zakwilson: I'm profiling some code I wrote with Yourkit and it seems to be spending most of its time doing swank.util.io/read-chars, but that makes no sense (it doesn't do anything with swank; swank just happens to be connected while I'm profiling it). Before I build a new jar without swank, is there a known issue?

22:54 mec: it could just be blocking on read and since its always sitting there just seems to take the most time

22:54 but that is just completely a guess

22:59 zakwilson: Doesn't seem to do that if I profile it at idle, and the CPU-intensive stuff I'm profiling doesn't call anything from swank.

23:05 mec: amalloy: its weird but even when a lot of computation happens in the loop, the version without it is equal or faster

23:07 amalloy: mec: have you tried it using my lazy-loop? i'm interested to see if other people think it makes things more readable or less

23:08 zakwilson: At idle, it spends all its time doing java.lang.Thread.sleep(), which is expected.

23:09 mec: amalloy: thats instead of using route* right?

23:09 amalloy: yeah

23:09 mec: ok let me try it

23:17 amalloy: i like it

23:17 amalloy: cool, thanks

23:18 mec: deffinitly beats having to put the args at the ass end of the fn

23:22 amalloy: mec: yeah, that readability improvement was a big motivator

23:24 mec: any other lazy tricks you'd like to share? :D

23:25 amalloy: mec: nah, lazy-loop is a pretty recent development for me. feel free to steal whatever you want from amalloy-utils though

23:58 mec: in emacs is there a way to auto indent 2 spaces anything with the form (fn [] instead of indenting to the leveling of the [

Logging service provided by n01se.net