#clojure logs

2011-04-10

00:11danbellI'm having trouble getting an example app to run through Tomcat;
00:12danbellsince clojure compiles straight to bytecode, it's hard to make sense of the stacktrace
00:12danbellany general tips?
00:12mecwould (eval `(~x ~@args)) be particularly slower than (apply x args)
00:14livingstonmec: i dont' know about in clojure but there are other considerations such as lexical scope when using eval in commonlisp
00:14livingstonis there a good reason not to use apply?
00:14mecx could be a macro
00:15mecwell seems to be about 21 times slower
00:15livingstonis it a function some is passing you? just make them pass you a function version or something.
00:16amalloyi've actually found a good (i think) reason to use that eval form, but in general it's a terrible idea
00:16livingstonthere'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.
00:16livingstonsame for macros, if there a reason to use them fine, but if a function fits, use that.
00:17livingstonsure there can be plenty of good reasons. lazy is a bad one though ;)
00:17amalloydanbell: (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
00:18danbellamalloy, as usual, is ridiculously helpful
00:18amalloythere's also clj-stacktrace, which purports to make stack traces more readable
00:30amalloymec: out of curiosity, what are the circumstances that make you want to use eval like that?
00:30mecplaying around with findfn
00:30amalloyhaha, that explains why you saw that eval form, i guess
00:30livingstonI 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)
00:32amalloywhile (x < 10);
00:32amalloy x++;
00:33amalloythe semicolon of doom
00:33livingstonok maybe not there. but that's your fault for not using squigglies
00:34amalloylivingston: well, that's not "in between statements", so your claim is still true
00:34livingstonthat's why sexpressions and prefix notation win again ;)
00:34livingstonI guess that's true too
00:34mec,(apply #'and [1 2])
00:34clojurebottrue
00:34mecwhy does that return true
00:35amalloy$source and
00:35sexpbotand is http://is.gd/pY0AD3
00:36amalloy&(#'and)
00:36sexpbotjava.lang.IllegalArgumentException: Wrong number of args (0) passed to: core$and
00:36livingstonlol
00:36mecweird
00:37amalloymec: it's calling the function behind the and macro, with 1 as &env, 2 as &form, and no "actual" args
00:37amalloy&(#'and 1 2 3)
00:37sexpbot⟹ 3
00:37amalloy&(#'and false false 3)
00:37sexpbot⟹ 3
00:38meccrazy
00:39livingston,(macroexpand '(apply #'and [1 2]))
00:39clojurebot(apply (var and) [1 2])
00:39mec,(apply #'and nil nil [true true false])
00:39clojurebot(clojure.core/let [and__3468__auto__ true] (if and__3468__auto__ (clojure.core/and true false) and__3468__auto__))
00:40mecok so i guess i'll stick with eval
00:40amalloymec: you definitely won't get what you want by applying a macro
00:40livingstonyou're quoting a macro
00:41amalloyi guess that's not true. you might want crazy, unpredictable results
00:41meci enjoy living on the edge
00:42pdkif you want crazy unpredictable results
00:42pdktry some c++ multithreading libraries
00:43livingstonI have enough fun with java and it's dumb libraries, I don't need to go back to freeing memory too, thanks.
00:44meci suppose it makes sense that the only way to expand a macro at runtime is with eval
00:45livingstonmacros are processed at read time. it doesn't know what to do if you try to fn'call one.
00:47amalloylivingston: otoh, they are just functions underneath, which is why ##(#'and nil nil x y) is the same as ##(macroexpand '(and x y))
00:47sexpbot((var and) nil nil x y) java.lang.Exception: Unable to resolve symbol: x in this context
00:47sexpbot(macroexpand (quote (and x y))) ⟹ (let* [and__3468__auto__ x] (if and__3468__auto__ (clojure.core/and y) and__3468__auto__))
00:48amalloy&(#'and nil nil 'x 'y)
00:48sexpbot⟹ (clojure.core/let [and__3468__auto__ x] (if and__3468__auto__ (clojure.core/and y) and__3468__auto__))
00:49livingstonhow do I ask an object what interfaces it implements?
00:50livingstonamalloy: sure it's a function, but it's a function that returns code
00:50amalloy&(supers (class []))
00:50sexpbot⟹ #{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
00:51livingstoner, sexpressions really that are then stitched into the code
00:51amalloyor if you want to test implementation of a particular interface, ##(instance? Runnable [])
00:51sexpbot⟹ true
00:52livingstonthat 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
00:52livingstonthanks
00:52ssiderisamalloy: wait, why is [] Runnable???
00:52amalloyssideris: because it's a function
00:53mec,([1 2[ 0)
00:53amalloy&([1] 0)
00:53clojurebotUnmatched delimiter: )
00:53sexpbot⟹ 1
00:53mecdoh
00:53amalloyhaha clojurebot looks like he's laughing at you
00:53ssiderisamalloy: thanks, didn't know that!
00:53livingston,(
00:53clojurebotEOF while reading
00:54livingstonI was hoping to get him to frown
00:54amalloy&([1 2[ 0)
00:54sexpbotjava.lang.IllegalArgumentException: Wrong number of args (0) passed to: PersistentVector
00:54amalloyheh
00:54meclolwut
00:54amalloysexpbot tries to clean up unbalanced expressions
00:54amalloylooks like the one he cleaned up caused some problems
00:55amalloy&(let [x 1) (inc x)
00:55sexpbot⟹ 2 ; Adjusted to (let [x 1] (inc x))
00:56ssiderisso basically nth is only necessary for lazy sequences like ##(nth (range 10) 2)
00:56sexpbot⟹ 2
00:57amalloyssideris: or for lists, or for cons chains, or for j.u.Lists, or...really anything but vectors
00:57ssiderisok
01:15livingstonhow can people program without repl? change, compile, run, *damn*, GOTO 10 ... this takes forever
01:23meci dont know how i ever programed without doc and source
01:24livingstonmec: show is the biggie for me in the repl
01:25livingstonprogramming in java is for the birds though - of all things it just yelled at me for giving it too much type information. gah.
01:25amalloyhaha clarify plz livingston?
01:26livingstonamalloy: 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
01:27amalloyyeah, 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
01:28livingstonI 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
01:28livingstonI 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
01:29amalloylivingston: try new j.u.LinkedList(theLazySeq).toString() maybe?
01:29amalloyi mean, even in clojure it's not "trivial" to print a lazy seq: ##(str (range 3))
01:29sexpbot⟹ "clojure.lang.LazySeq@7480"
01:29livingstonhow does the repl do it?
01:30amalloy&(pr (range 3))
01:30sexpbot⟹ (0 1 2)nil
01:31livingston,(str (seq (range 3)))
01:31clojurebot"(0 1 2)"
01:31livingston&(str (seq (range 3)))
01:31sexpbot⟹ "(0 1 2)"
01:32livingston?
01:32amalloy? ? ???
01:35livingstonyep I cast it to ISeq and called .seq() on it and out it comes. Still doesn't seem elegant though.
01:37mecomg 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
01:38amalloycongratulations, you now have permission to join the super-secret #clojure-awesome room
02:14livingstonwell good night and thanks everyone
02:48HavvyIn Swank/Slime, how do you get it to tell you the line number the error was found on?
02:57amalloyHavvy: if it knows the line number, it tells you
02:59zakwilsonDoing 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.
03:01shachaffunction clj() { fanspeed max; clojure "$@"; fanspeed auto; }
03:01HavvyI 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. :/
03:01amalloyzakwilson: are you objecting that, when you ask clojure to use your cpu, it uses your cpu?
03:02shachafClearly Clojure isn't CPU-efficient, which means the CPU heats up more than it does with other languages.
03:02amalloyHavvy: when there are exceptions during macroexpansion, iirc swank can't tell what line they're on
03:02amalloyor, at any rate, C-c C-k can't; if you eval just a single form instead of the whole file, that sometimes helps
03:02zakwilsonWell... 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.
03:03HavvyI'd love stacktraces to remove all of the invokes though. Pure noise to me...
03:03zakwilsonI AM complaining that my laptop doesn't ever set the fan to full-speed automatically, but any more on that would be off-topic.
03:04HavvyAnyways, 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?
03:04amalloyHavvy: clojure.walk/{pre,post}walk are probably what you want
03:04amalloyor clojure.walk/walk if you need more fine-tuned operation
03:07HavvyThanks.
03:23seancorfieldmap vs pmap question...
03:24seancorfieldwith map, operations only use 100% CPU on my quad core (therefore only one CPU) as i'd expect
03:24seancorfieldwith pmap, operations use 400% CPU (all four cores) as expected
03:24seancorfieldhowever, pmap often takes LONGER to complete an operation than map
03:25seancorfieldis the overhead on doing parallel operations really that high?
03:25amalloyseancorfield: split your task into fewer subtasks, each of which is larger
03:25amalloy(yes)
03:25seancorfieldmy test case was a slow function that did 1,000,000 operations internally
03:25seancorfieldand map that over 100 elements
03:26seancorfieldmap took about 15 seconds every time
03:26seancorfieldpmap took 5 seconds the first time but then longer and longer on each subsequent time
03:26amalloy*eyebrow*
03:26seancorfieldso i assume i need more heap...
03:26seancorfieldbut, seriously, that was not what i expected :)
03:27amalloywhat do you mean, "every time"? every 1M operations, or every 1M*100 operation*partitions?
03:28seancorfield(dotimes [_ 10] (map expensive (repeat 100 1)))
03:28seancorfieldthat took 15 x 10 seconds
03:28seancorfield(map expensive (repeat 100 1)) takes 15 seconds
03:28amalloyokay
03:28seancorfield(pmap expensive (repeat 100 1)) takes 5 seconds on a clean jvm repl
03:29seancorfieldbut takes 10 seconds the second time, then 15 seconds, then 20 seconds
03:29seancorfieldso (dotimes [_ 10] (pmap expensive (repeat 100 1))) takes a looooong time
03:29seancorfieldinstead of just 50 seconds
03:29amalloyseancorfield: are you sure you're actually forcing all the results?
03:29amalloytry (comp doall pmap)
03:30seancorfieldyeah, i'm actually doing a (reduce + ... ) on it, sorry
03:30seancorfieldbut (reduce + (map expensive (repeat 100 1))) was very consistent at around 15 seconds
03:30amalloyhm. "shouldn't" be any memory left over afaict
03:30seancorfieldwhen i did it with pmap, it would always take about 5 seconds the first time
03:31amalloy$source pmap
03:31sexpbotpmap is http://is.gd/mVHNdG
03:31seancorfieldand then longer and longer on subsequent times
03:32seancorfieldanyways, i was mostly just curious how many people were using pmap and what they were seeing
03:32amalloyseancorfield: i used it once, last fall, when i was working on some computationally-intensive stuff
03:32amalloyslowed me down when i used it naively, gave a moderate speedup when i used it sensibly
03:33seancorfieldso maybe my problem is memory usage?
03:33amalloymaybe, but i can't see why the first run would be any different speed-wise
03:34amalloyor memory-wise
03:35seancorfieldi'll dig some more another day...
03:35seancorfieldi wanted to use it as an example in a presentation but i can't get it to behave reliably :(
03:37amalloywhile nobody's looking try (def pmap (constantly the-value-you-expect))
03:37amalloyought to be fast enough
03:38seancorfieldhere's my test code:
03:38seancorfield(defn expensive[n] (reduce + (repeat 1000000 n)))
03:38seancorfield(time (reduce + (map expensive (repeat 100 1))))
03:38seancorfield(time (reduce + (pmap expensive (repeat 100 1))))
03:39seancorfieldand that gives expected results
03:39seancorfieldbut if you add dotimes around the reduce, the pmap slows down on subsequent evaluations
03:40seancorfieldas written:
03:40seancorfield"Elapsed time: 25416.303 msecs"
03:40seancorfield"Elapsed time: 7165.128 msecs"
03:41seancorfieldnow change it to:
03:41seancorfield(defn expensive[n] (reduce + (repeat 1000000 n)))
03:41seancorfield(time (dotimes [_ 2] (reduce + (map expensive (repeat 100 1)))))
03:41seancorfield(time (dotimes [_ 2] (reduce + (pmap expensive (repeat 100 1)))))
03:42seancorfieldand you get:
03:42seancorfield"Elapsed time: 49866.352 msecs"
03:42seancorfield"Elapsed time: 40540.13 msecs"
03:42seancorfieldthe map behavior is consistent: 2 x 25s is about 50s
03:42seancorfieldbut pmap goes from 7s to 40s... which means the second run takes 33s???
03:43amalloyseancorfield: or, if you're using the same repl still, both of those two are slower
03:44seancorfieldwell, yes... but really? why would pmap slow down when run multiple times?
03:44seancorfieldeach run was on a new repl... i'm running it with 4x now... just to see...
03:44amalloyi'd probably say ask on the mailing list. my best guess is that Thread objects are expensive?
03:45seancorfieldlol... i will ask on the mailing list :)
03:45seancorfieldbut if thread objs are expensive, why is the single run so fast?
03:45seancorfieldok, 4x shows map at "Elapsed time: 97701.973 msecs"
03:45seancorfieldwhich is exactly what is expected
03:46seancorfieldstill waiting for pmap run to finish :)
03:53amalloy$source future
03:53sexpbotfuture is http://is.gd/9xaEGV
03:54amalloyi wonder if the future objects somehow aren't being marked as "done"
03:57amalloyseancorfield: my aging 2-core machine does not thank me for pasting your code
03:58seancorfieldlol sorry :)
03:59markomani 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
04:02markomaneach 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
04:03amalloyseancorfield: fwiw i see similar behavior, on 1.2.0
04:04markomanI 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?
04:05markomanshould I use clos/oo with this or just pure functions, maybe macros
04:06markomanI need to have flexible system, so that new question types are easily to be added later
04:07no_mindhow 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)
04:07no_mind"
04:09amalloyseancorfield: 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
04:12Havvy,(.split "This is a test message FOR sure!" " ")
04:12clojurebot#<String[] [Ljava.lang.String;@82190a>
04:13HavvyHow can I get it to show the actual string?
04:13HavvyErr, array of strings...
04:14amalloy&(seq (.split "This is a test message FOR sure!" " "))
04:14sexpbot⟹ ("This" "is" "a" "test" "message" "FOR" "sure!")
04:14HavvyAh. That seems a bit annoying.
04:15markomanif 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
04:16amalloyHavvy: feel free to change the source code of java.lang.String.toString
04:16amalloyer, String[].toString
04:16HavvyErm, that sounds like a scary prospect.
04:16HavvyCreating a wrapper function is easier.
04:16amalloyindeed, i would characterize it as not possible
04:19amalloyalso, seq is already a wrapper function
04:19amalloyand if you want clojure-friendly structures, use clojure functions instead of String.split
04:19HavvyIs there a clojure function that acts as String.split?
04:19amalloy&(doc clojure.string/split)
04:19sexpbot⟹ "([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."
04:20HavvyExcellent.
04:20amalloysee also ##(doc re-seq)
04:20sexpbot⟹ "([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."
04:25HavvyI feel both newbish and noobish. :(
04:28amalloyre-seq is pretty sweet
04:29amalloyif you have a reason to use regexes, anyway
04:30markomanim 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}")))
04:31HavvyIt is prettys sweet, and the example on cojuredocs even does what I want. :P
04:31markomanor actually load should be called before calling mode but anyway
04:37markomanor 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
04:38seancorfieldamalloy: thanx for trying that code... the 5 min away time is very interesting
04:38seancorfieldthat suggests i just need more heap (and let java GC things in between)
04:38amalloyseancorfield: i think it may have been an illusion. just tried it after like 20 minutes and it took longer ;P
04:39seancorfieldhahaha... ok... so it _is_ broken then? :)
04:39amalloyprobably
04:39amalloywho knows
04:39seancorfieldbtw, where in the world are you to be online at this time?
04:39markomanmy next try would be something like this: (defn form-question-get [type mode & args] (use 'forms.qtypes/{type}) (mode args))
04:39amalloysan francisco, and stupid
04:39seancorfieldoh, you're that local to me?
04:40amalloyyou were at the clojure meetup, right?
04:40seancorfieldi'm in castro valley
04:40seancorfieldyeah
04:40seancorfieldwell, not at the april 7th one
04:40seancorfieldi was at the CI Summit at linkedin
04:40amalloyi was at the last two
04:40seancorfieldbut yeah i've been at some of the bay area clojure meetups
04:41seancorfieldbummed i missed clojureconj last year... but i _will_ be at it this year come hell or high water!
04:41amalloyyeah, same
04:42seancorfieldi was in england for the march one
04:42amalloyat the time i was just picking up clojure, seemed a little too hardcore for me to go to the conj
04:42seancorfieldi was in albuquerque :(
04:42seancorfieldi had a cat show in ABQ then Adobe MAX in LA
04:43seancorfieldthis year i'm doing scala days, strange loop and clojure conj
04:43amalloyoh, i was trying to figure out where in england albequerque is
04:43seancorfield:D
04:43seancorfieldi was speaking at a conference in scotland
04:43amalloythat's not in england either
04:43seancorfielddallas, then scotland... home for a bit... then speaking in minneapolis...
04:44seancorfieldi'll be bloody glad when my "conference season" is over!
04:44amalloyfortunately nobody thinks i'm interesting enough to hear me talk
04:45seancorfieldi enjoy attending conferences more than speaking at them
04:46Havvyamalloy: That is not true. I would love to see a talk by you.
04:46amalloyHavvy: alas, i spend more time helping out in irc than doing actual things
04:47HavvyAlas, I know the feeling all too well.
04:48HavvyPerchance, do you know how to get parenthesis to colorize in a default Clojurebox setup?
04:48amalloyclojurebox is...what, emacs?
04:48Havvy23.1 of emacs, but yeah, emacs.
04:48amalloy$google emacs rainbow paren
04:48sexpbotFirst out of 181 results is: clojure - How do I get "rainbow parentheses" in emacs? - Stack ...
04:48sexpbothttp://stackoverflow.com/questions/2413047/how-do-i-get-rainbow-parentheses-in-emacs
04:50amalloyanyway seancorfield, thanks for the reminder re time. unlike today, i have to be awake tomorrow morning
04:50HavvyNight amalloy, and once again, thanks for the help.
04:50amalloyta-ta Havvy
04:50seancorfieldme too... gotta get up early and do litter boxes :(
05:47TotramonI'm having a problem with a "Too many arguments to def" exception when 40-something iterations into a loop
05:51TotramonI wonder what could break after so many iterations?
05:52Totramonand with such an exception msg
05:52angermanTotramon: what does your code look like?
05:55Totramonwell, I'm implementing a genetic algorithm so it's a lot of code
05:55jwr7Is 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)
05:55angermanTotramon: what's the code arround the error?
05:56Totramonbut well the outer loop is a loop - do - print - recur
05:56jwr7Basically, clojure complains about (aget arr i)
05:56TotramonI do not know what triggers it - the exception comes from repl
05:57Totramonthe most recent item on stack trace is clojure.lang.Compiler$DefExpr$Parser.parse (Compiler.java:415)
05:57angermanTotramon: don't look at the most recent, scan the stacktrace for parts that contain your file.
05:58Totramonthere's nothing related to my code in it
05:58Totramonhm, could there be a time limit to execution?
05:58angermanwithout you setting it? not that I know of.
06:01Totramonthis is the output from the exception: http://pastie.org/1778250
06:03angermanthat's all?
06:03angermanwow.
06:03Totramonyes
06:03TotramonI'm using eclipse and counterclockwise btw if that's of any relevance
06:03angermanthen this must be an issue with a def definition.
06:04angermanat some point you give (def ) more then 2 arguments.
06:04angermanmaybe somewhere there is an (apply def )? or some other function composition.
06:05angermanNot that I'd understand why one would do that but, it could be a possibility.
06:05TotramonI don't think I use an explicit def anywhere
06:05angermanwell, without code and how you invoke it, I'm lost here.
06:06Totramonok. this really starts to look like a timelimit issue, because it fails exactly after 60 seconds every time
06:06Totramonlet's see...
06:06angermanI really don't think that the base repl inferes any timeout. Maybe it's counterclockwise or eclipse.
06:08Totramonok I need to see if I can find such a setting somewhere
06:09angerman(or run it from command line ...)
06:09angermanor try something like (Thread/sleep 80*1000)
06:09angermanI still doubt it though.
06:13Totramonsleeping for 80 seconds didn't cause an exception
06:13Totramonalthough, it didn't return a nil, either
06:39Totramonoh, but of course... the stack trace was for a random exception
06:40Totramonwhen the execution failed it didn't except at all
06:41Totramonso actually the only error I get is "Expression failed <however I called it>"
06:42Totramonfound a relevant post now, too. thanks for help anyway
06:43Totramonccw does have an evaluation timeout of 1 minute
06:44Totramonthink I need to switch away from the RC version for now
07:21codsIs there a shortcut for (map (fn [o] (.myMethod o)) seq) ? I tried (map .myMethod seq) which is rejected.
07:22codswell, I could do (map #(.myMethod %) seq)
07:22codswhich is short enough for me
08:22fliebelWhere does the ants demo by Rich live? I believe someone updated it a bit?
08:24fliebelAh, maybe this one?
08:24fliebelhttps://github.com/krukow/ants-demo
10:14mechow might i write a macro to turn (f a b) into (f 'a 'b)
10:16Vinzentsomething like `(quote ~arg) ?
10:17TimMcmec: (some-macro f a b) -> (f 'a 'b) is what you want?
10:18mecyes
10:18TimMcI'm not sure why you wouldn't just write (apply f '(a b))
10:18mechmm indeed
10:19mec$findfn '[x 5] 'x 5
10:19sexpbot[clojure.core/let clojure.core/loop clojure.core/when-let clojure.core/if-let]
10:19mecbasically I dont want to have to do that
10:22TimMcbut... (defmacro foo [f-expr & arg-syms] `(apply ~f-expr '(~@arg-syms)))
10:33mecwell so much for that, doing it kills the ability to process regular functions
10:40mecIs there a better way to do (juxt last butlast) that wont run the seq twice
10:45TimMcmec: Are you talking about lazy seqs, or about just needing to potentially walk through the whole thing?
10:46mecjust walking it twice
10:46TimMck
10:46mecright now i've just got #((juxt peek pop) (vec %))
10:46TimMc*nod*
11:12mecis there a version of keep that only keeps truthy values?
11:14fliebelmec: Isn't that what keep does?
11:14meckeeps false values also
11:14TimMcmec: filter identity :-P
11:15TimMcjust filter might be what you want
11:16TimMcI guess the question is whether you want to keep the inputs or the outputs of your predicate.
11:16meci guess i can just adjust the predicate to not return false
11:22TimMc$findfn identity '(nil false 1 true) '(1 true)
11:22sexpbot[clojure.core/filter]
11:23mec,(str (doall (range 10)))
11:23clojurebot"clojure.lang.LazySeq@9ebadac6"
11:27fliebel&(str (seq (range 10)))
11:27sexpbot⟹ "(0 1 2 3 4 5 6 7 8 9)"
11:49fliebelI need to merge multiple maps into one, but not just accumulate keys and the last wins, but more like git-style.
11:52fliebelSo 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:52TimMcfliebel: The value are all numbers that are manipulated with addition?
11:53fliebelTimMc: No.
11:54TimMcHow will you know that y was incremented as opposed to scaled?
11:54fliebelTimMc: I just care about changed, if both maps had :y changed, last-wins is okay.
11:54fliebel-ish
11:55fliebelI can think of something with clojure.set for changes, but I struggle with the deletions.
11:57TimMc(difference (set (keys a)) (set (keys b)))
12:00fliebelwell… 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:00fliebel*reversed
12:06TimMcfliebel: select-keys is your friend here
12:07fliebelTimMc: 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:07TimMcHmm, that works too.
12:17fliebelweee! 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:18fliebelTimMc: ^
12:19shachaffliebel: Instead of finding it mildly annoying, find it deeply infuriating. Then you'll care enough to fix it.
12:20shachafThat's what I do, anyway.
12:21TimMcfliebel: nice
12:37xkbhi
12:37xkbI'm trying to fix this macro: https://gist.github.com/912494
12:37xkbwhere func should be the literal name of a function
12:38xkbI tried slicing and slice-unquote, but I think I'm missing something as I keep getting error messages
12:38xkbeven on expand, esp. when I give something like Library/addArtist (a Java static method) as input parameter
12:38xkbany idea what I'm doing wrong?
12:39Chousukexkb: you want (~func ~@args), most likely
12:40xkbso without apply?
12:40Chousuke(apply func ~args) expands to something like (apply func (arg1 arg2 arg3))
12:40xkband that's what I want
12:40Chousukeno you don't :)
12:40xkbapply func to the arguments
12:40Chousukeyou don't want to call the first arg as a function
12:40Chousukewith my form, you'll get (func arg1 arg2 arg3)
12:41xkbthat's equal to (apply func (list arg1 arg2 arg3)) right?
12:41__name__Since when does Clojure have ~?
12:41Chousukeyes?
12:41Chousuke__name__: ~ is unquote
12:41__name__Ah.
12:43Chousukexkb: note that (apply func (list arg1 arg2 arg3)) is not the same as (apply func (arg1 arg2 arg3)) :)
12:43xkbargs is a list, due to & right?
12:43xkbso args actually is (list ....)? Or is that a wrong assumption?
12:44Chousukehm
12:45xkbI think I'm missing something, can't really point out what though
12:45Chousuke,((fn [& args] `[args ~args ~@args]) 'some 'args 'here)
12:45clojurebot[sandbox/args (some args here) some args here]
12:46Chousukethat's what gets used as the code
12:47xkbso I want the second, ~args I presume
12:47xkbas is in my code now
12:47Chousukeno
12:47xkbor without apply, the third
12:48Chousukebecause then your code will end up being (apply func (arg1 arg2 ...))
12:48Chousukeand (arg1 arg2 ...) is a function call form
12:48xkbahh yes
12:48xkbhmm 2 bad :) I had hoped to abuse the () form to append one extra argument
12:49Chousukeyou can also do (apply func ~(cons `list args))
12:49Chousukeor (apply func ~(vec args))
12:49xkbah yes
12:50xkbjust delay the splice
12:52xkbanyway, 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:52xkbcalled like this: (macroexpand-1 (with-error-handling (fn [a b] (Library/addArtist a b)) "OK" "FAIL" "Murk" (get-session)))
12:52xkbah.. that anonymous
12:53xkbthat's even
12:55fliebelIs there any way to kill a loop in lein without killing lein?
12:55Chousukexkb: you need to unquote the func too.
12:55xkbChousuke: thanks for the help!
13:02xkboh, 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:12Chousukexkb: did you remember to quote the form that you macroexpand?
13:12Chousuke,(macroexpand-1 '(fn [] test))
13:12clojurebot(fn* ([] test))
13:14xkbah I forgot the quote
13:14xkbthanks again
13:31mecfliebel: what did you end up using to merge your maps?
13:54markomanhow can I do this kind of operation on clojure: (use 'lib.sublib."file")
13:55markomanthe last part of the use is changing so practically if I have a library path on string format, how can I "use" it?
13:57markomani could perhaps provide last part in format (use 'lib.sublib.:my-file) too
14:06fliebelmarkoman: Maybe (use ['lib (symbol "sublib")])
14:06fliebeloh, wait, load-ile probably.
14:06fliebel*load-file
14:07markomanthere might be several loads for same file, does that matter?
14:08fliebelmarkoman: Multiple invocations of load-file will not return the previous result.
14:09fliebelMaybe you could memoize it :)
14:10markomanha, ive seen that word, memoize but dare not to find out, what it means
14:10fliebelmarkoman: 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:11markomanhmh, so far sounds like it could fit in this case
14:12fliebelmarkoman: Note that load-file doe not refer the loaded code, so it is not like use.
14:12markomanI 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:13markomansee, I have this kind of situation: (defn form-question-type [type callee & args] (use '(str "magicforms.qtypes." type)) (callee args))
14:14fliebelmarkoman: w-wait, what am I conspiring in now? That sound quite bad, using use in a fn.
14:14markomanyes!
14:15markomanim experimenting it on repl and so far no idea, what I should do with it
14:15fliebelSo you want to require stuff as you need it?
14:15markomanexactly, and I may need it zero, one or n times
14:16fliebelhow much of these are there? Is it worth the trouble lazy-loading them?
14:16fliebelYou could also look into delay.
14:17fliebel(def t (delay (require the.type))) @t @t will require it once.
14:18markomanim not sure about worth, but qtypes, its increasing library and files. all files has same functions like: create, list, show, etc
14:18fliebelah, as long as you use require instead of use, that is not a problem/
14:19fliebelthen you write qtype/create
14:20fliebelYou can even alias these: (require '[blah.qtypes [foo :as f]]) (f/create)
14:51markomanfliebel: my connection broke, so did conversation in the middle...
14:54raekmarkoman: speaking of lazy code loading: http://groups.google.com/group/clojure-dev/browse_thread/thread/025821cbbfa47226#
15:03markomanraek: how does that affect to use, require?
15:04raekI merely know that this exists, nothing more... :)
15:05raekit struck me as a potential solution to "So you want to require stuff as you need it?"
15:07raekmarkoman: so, why do you need to dynamically load code?
15:07markomanhmh... 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:07markomanlet me try to explain that
15:08raek...or why is does not a :require in the ns do the trick in your case?
15:08markoman(defn form-question-type [type callee & args] (require '(str "magicforms.qtypes." type)) (callee args))
15:09markomanit probably does, i was using use as a first sketch, but guessed it may cause name pollution or other problems
15:10markomani 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:10markomanor = of
15:11raekI think there are simpler ways of representing the question types than namespaces
15:12choffsteinHey all. I have a quick question. I keep getting an arity error, but I can't figure out why.
15:12choffsteinI'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:13raekmarkoman: this cannot work, since before a function is compiled, all vars it uses (e.g. fns in other namespaces) must be loaded
15:13markomani 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:13choffsteinAny ideas why this may be happening?
15:13raekwell, technincally, the vars need to exist
15:14raekchoffstein: I don't see anything strange in that snippet there
15:14trptcolinchoffstein: what raek said. what's the caller look like?
15:15raekmarkoman: is there any reason you can't store everything in ordinary clojure data structures?
15:15markomanraek, but if there are no vars, just function on each qtype file?
15:15raekvars in namespaces is what "names" functions...
15:16raekwhen you have (defn foo [] (bar)), bar is a reference to the bar var, not the function it holds
15:16choffsteintrptcolin: like (f 1 2 3)
15:16markomanraek, 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:16choffsteintrptcolin: I'll gist it
15:16raekyeah, in python, a module is basically just an object with attribues
15:16raekin clojure, that is not exactly the case
15:17raekso clojure is more "compily" in this aspect...
15:17trptcolinchoffstein: cool
15:18markomani 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:18raekI would recomment having a global var holding some data structure that contains that stuff
15:19choffsteintrptcolin: https://gist.github.com/912628
15:19choffsteintrptcolin: first-date, (get (:data file-data) first-date), and initial-index-value all evaluate correctly.
15:19trptcolin:) haha, "..." indeed
15:19markomanim 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:20raekyou could have a map like {:foo {:create (fn ...), :list (fn ...), :show (fn ...), :validate (fn ...), :search (fn ...)}, :bar ...}
15:20choffsteinAnd the error is: Wrong number of args (2) passed to: core$construct-index-by-pct$shares-on-date
15:20devnclojure project! https://github.com/codahale/metrics
15:20devnscala -> clojure
15:20choffsteintrptcolin: actually, hold on. the whole file is up on github. let me find it.
15:20raekremember that it is possible to store functions in data structures too :)
15:21choffsteintrptcolin: https://github.com/newfoundresearch/construct-index/blob/master/src/construct_index/core.clj -- in construct-index-by-pct
15:21raekmarkoman: 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:21choffsteintrptcolin: don't be too harsh on the code -- it is my first run through on it. just getting it to work before refactoring
15:21markomanyeah, 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:22trptcolini won't be :) i'm just thinking it'd be easier to debug with functions split out to remove dependencies
15:23choffsteintrptcolin: 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:23raekmarkoman: perhaps you can have an namespace that acts as an api with functions for adding qusetion types?
15:23raekmarkoman: I have a feeling that what you do is similar to how 'derive' works in clojure
15:24raekit allows libraries to add stuff to a global hierarchy
15:24markomanprobably, i need to check google
15:26raekit could be as easy as having (def types {}) (defn register-type [name stuff] (alter-var-root #'types assoc name stuff))
15:27raekor if things change at runtime: (def types (atom {})) (defn register-type [name stuff] (swap! types assoc name stuff))
15:27trptcolinchoffstein: i wonder about this line: "(reduce #(+ %1 (Double/parseDouble %1)) 0 data-row)"
15:27trptcolin,(reduce #(+ %1 %1) 0 [1 2 3 4 5])
15:27clojurebotjava.lang.IllegalArgumentException: Wrong number of args (2) passed to: sandbox$eval5396$fn
15:28trptcolinyou probably want a %2 in there somewhere
15:28choffsteinahhhh, yes
15:29choffsteinyou, sir, are a genius!
15:29trptcolinit'd be nice for that error message to give some clue that the fn in question is anonymous *under* the fn it gives...
15:30trptcolinbut 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:30raekmarkoman: if you have something like that, other namespaces can add types. splitting code into managable chunks is always a good idea...
15:31markomani dont think I let types change at runtime, when new types comes in, I need to deploy anyway. its just for code management
15:32trptcolindevn: that looks pretty tasty
15:32markomanI 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:36markomanoraek: but you still mean I need to register all question types on same types map?
15:37raekmarkoman: 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:38raekmaybe it helps to think of vars in namespaces to be static
15:40markomanok, 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:41raekalso, will the namespaces only contian data (and no code)?
15:41raekif so, it might simply be better to load data from some files
15:41markomanso I could escape from duplicate writing because all qtype filenames are already qtypes
15:42markomanwell because data structure can hold functions, it would be only data :)
15:44raekits probably possible to scan a directory on the CLASSPATH for .clj files and load them
15:44raekbut as a start, it is probably easier to just list them in the :require form in some namespace
15:45markomanok 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:46raekI 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:57markomanraek: btw why you use alter-var-root and not just (types assoc name stuff) ?
15:59mreynoldsnewb 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:00raekmarkoman: 'types' contains a map, and calling it as a function won't do what you think
16:01raek(m key) (m key default) are the same as (get m key) and (get m key default)
16:01mreynoldsA 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:02trptcolinmreynolds: use and require are generally for vars - if you're using defrecord/deftype you'll need import as well
16:02raekmreynolds: are we talking about methods and classes (java land) or functions and namespaces (clojure land)?
16:03mreynoldstrptcolin: Thanks, that's what I just realized wasn't working. I need import because it's creating real Java classes?
16:03trptcolinyep
16:03mreynoldsraek: 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:04raekmreynolds: you should not get CNFE for clojure-only stuff
16:05raekimport is only for shortening the name of java classes (and is not used for namespaces)
16:05mreynoldsraek: Hmm
16:05raekso, I assume you files looks something like this:
16:06raekin file src/a/foo.clj: (ns a.foo) (defn hello ...)
16:06mreynoldsSo, 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:07raekin file src/a/bar.clj: (ns a.bar (:use [a.foo :only [hello]])) (def blah [] (hello))
16:07mreynoldsI'm double-checking for typos, but the import seems to be not working
16:07raekah, I see
16:07trptcolin(:import [com.examples.x.y.z Location])
16:07trptcolin(needs the vector)
16:07raekyou need to both require the namespace that defines the record and then import the class
16:07mreynoldstrptcolin: That's it. Thanks. I need to create a cheat sheet for that.
16:07mreynoldsimport doesn't do both, eh?
16:07mreynoldsWeird
16:08mreynoldsOr, weird to my yet-to-be-trained-brain
16:08raeksorry for misleading you. you can indeed get CNFE this way...
16:08raekthis is a known problem
16:08mreynoldsraek: no worries
16:08trptcolinyeah, records are a bit fussy wrt nses...
16:08mreynoldsraek: I've dealt with Java for so long, this actually seems happy and warm and soft
16:09mreynoldsI think I get the underlying issue, mainly that records are official objects, get created as such, and this need to be imported
16:09mreynoldsRather than "used"
16:09raekI common workaround for this is to let the user use a constructor function, instead of the record class constructor
16:10mreynoldsraek: Yeah, I read that in the Joy of Clojure (I think), and plan to switch to that now
16:10raekhttp://dev.clojure.org/display/design/defrecord+improvements
16:11mreynoldsraek: Thanks!
16:12raek(import only affects how symbols are resolved the namespace, and doesn't do any loading)
16:13raek*in the
16:14mreynoldsRight, 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:15mreynoldsimport :: java, use :: directly in ns, require :: referenced via keyword
16:15mreynolds?
16:18raek(import 'javax.swing.JFrame) only causes JFrame symbols to resolve into javax.swing.JFrame in the current namespace
16:18raekrequire and use on the namespace foo.bar causes the file foo/bar.clj to be evaluated if it hasn't been already
16:19mreynoldsraek: Tangential question - Why use 'javax.swing.JFrame vs (javax.swing JFrame)?
16:19mreynoldsah, good to know about evaluation
16:19mreynoldsI have read this stuff, but it's not sticking immediately, sorry for the newb questions
16:19trptcolinthose are equivalent, but you might want (javax.swing JFrame Icon Action)
16:19raek'(javax.swing JFrame) is easy to change into '(javax.swing JFrame JLabel) :)
16:20trptcolinword
16:20trptcolinmreynolds: 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:20raekuse, but not require, will cause all the vars in that namespace to be available without a complete namespace prefix
16:20mreynoldstrptcolin: I'll go read that
16:23mreynoldsOh, 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:24mreynoldsI 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:25choffsteinCan I check if a Java Date is in a collection using contains?
16:25choffsteinIt doesn't seem to be working for me and I can't figure out why
16:25trptcolinwhat kind of collection? :)
16:25raekclojure 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:26choffsteinlist
16:26raekchoffstein: 'contains?' should be read 'has-key?'
16:26trptcolincontains? may not work as you expect for things other than sets & maps
16:26clojurebotTitim gan éirí ort.
16:26choffsteinahhhh
16:26choffsteinwell, that explains it then!
16:27choffsteinis there a way to check if a list contains an element?
16:27raekto do a linear seatch for the element, use (some #{elemenent} coll)
16:27raekbut if you search for elements in the collection often, you might want to consider to use a set as the datastructure
16:28raeksince those are specialized in checking membership
16:28choffsteinraek: yeah, a set would be much better
16:48markomanso i got this far: (:search (qtypes :single-select) "args1") it returns the function, but how do I actually execute it?
16:48brehaut((:foo {:foo inc}) 1)
16:48brehaut,((:foo {:foo inc}) 1)
16:48clojurebot2
16:49markomancool, thanks
17:17markoman(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:17markomanis there some smarter way to do this, because I see its going to repeat again and again for different elements
17:28seancorfieldmarkoman: maybe use named arguments with defaults instead?
17:29Deranderis there a way to pass -Xms and -Xmx args through lein swank to increase heap size?
17:29markomanthis is the way i though it is done in clojure :)
17:32seancorfield(defn element [name & { :keys [value id options] :or {value nil id nil options nil}}] (println name value id options))
17:32seancorfield(element "n" :value "v" :id "i" :options "o")
17:32seancorfield(element "n")
17:32seancorfield(element "n" :id "i")
17:33raekmarkoman: it is the only way to do it if you want it to only allow the arities you specify
17:33seancorfieldpity you can't have a [name value id options] :or [nil nil nil nil] sort of destructuring...
17:34raeksomeone should make a macro for this...
17:34markomani think I once saw related macro...
17:37raek(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:51markomanclojure.contrib.def/defnk could work?
17:53seancorfielddefnk would provide syntactic sugar vs what i was suggesting, yes
17:58markomanalright, its time to sleep. thanks sean and raek for your insights
17:58seancorfieldhere's a version with optional positional args:
17:58seancorfield(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:58seancorfield(defn args-to-map [ names values defaults ] (apply hash-map (apply concat (map list names (make-default values defaults)))))
17:59seancorfield(defn make-default [values defaults] (if values (cons (first values) (make-default (next values) (next defaults))) defaults))
17:59seancorfieldi'm sure there's much cleaner versions of those two helper functions
17:59markomanso its much talked about syntactic sugar, but what is syntactic salt then?
17:59seancorfieldbut a little macro magic could make it much cleaner
18:02markomani see, i need to copy that for tomorrow and see how things work
18:46mecdoes destructuring change the collection type?
18:47brehautmec: 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:47brehautmec: otherwise you get the elements as they are in the collection
18:48mecah, so i shouldnt destructure a queue
18:48brehautmec and the collection itself doesnt change due to the destructuring
18:48brehautmec: it depends/
18:49brehautmec: in particular it depends on what sort of queue you are using
18:49mecPersistentQueue
18:49brehautmec then i cant see it being a problem
18:50brehautmec: unless you want to just treat the remainder as a queue
18:50mecif I do (let [[x & rqueue] queue] ...) if it changes rqueue from a PersistentQueue then i wont be able to keep using it
18:50brehautrqueue is never a persistentqueue
18:51brehaut,(destructure '[[x & r] [1 2 3]])
18:51clojurebot[vec__5404 [1 2 3] x (clojure.core/nth vec__5404 0 nil) r (clojure.core/nthnext vec__5404 1)]
18:51brehautmec: you can see that r is bound to the result of nthnext
18:52mecah ok
19:24mechow might I conj 2 items onto a collection so that if either is nil that one wont be added
19:25mec(into coll (filter identity [x y])) i guess but i just hate filter identity for some reason
19:32mreynoldsI 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:37mecregistered-plugins is a vector of agents?
19:37mreynoldsmec: Set, actually
19:37mreynoldsmec: Er, it's a set, held by an agent
19:38mreynoldsmec: Er, wow, sorry. Vector held by an agent.
19:38mec(-> event (registered-plugins)) is just (registered-plugins event) but if registered-plugins is an agent you would need (@registered-plugins event)
19:39mreynoldsI'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:39mreynoldsmec: oh, neat
19:39mreynoldsmec: Lemme try that
19:41mreynoldsmec: I must be doing something dumb because that seems to be treating event as an index into the vector
19:41mreynoldsmec: the contents of the vector are functions, if that helps
19:42mecoh and you want to run each function with event as arg?
19:42mreynoldsyeah, sorry
19:42mreynoldsmec: Brain is getting a bit worn
19:43mec((apply juxt @registered-plugins) event)
19:43mreynoldsmec: It feels like a pretty simple problem, but I have too many levels of indirection I'm not familiar with yet.
19:43mreynoldsI'll try that
19:45brehautmec: perhap you would prefer (remove nil? col) ?
19:47brehautmreynolds: (map #(%1 event) @plugins-agent) ?
19:47mecbrehaut: I thought about that one, but that juxt just looks beautiful
19:49brehautmec: im not sold on it for this usage
19:49mreynoldsmec: That worked
19:49meche mentioned map being lazy so it saves an extra (doall)
19:49mreynoldsbrehaut: Almost worked, but didn't print... I think it's a lazy issue between the two styles?
19:50mecmreynolds: for the map you gotta wrap it in a (doall (map ..)) for side effects
19:50mreynoldsmec: Yup
19:50mreynoldsthanks
19:50mreynoldsIs there an easy way to tell that a chain is lazy and won't be called?
19:50mreynoldsI mean, normally, that's awesome
19:51mreynoldsFor debugging purposes, with println, it's not so awesome
19:51brehautmreynolds: know what your data is?
19:52mreynoldsbrehaut: 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:52mreynoldsDid I answer your question?
19:52brehautmreynolds: nope; i mean that you need to know what your data is to know when it needs to be realized etc
19:53mreynoldsbrehaut: Sorry, not sure what "realized" means in that sense
19:53brehautmreynolds: a lazy computation is only evaluated when it is realized
19:53brehautrealization is the process of taking that thunk and replacing it with the computed result
19:53mecpretty much if you use any of the core collection functions, its going to be lazy
19:53mreynoldsbrehaut: Gotcha. I think I need a way to force that for debugging purposes and I'm not sure how to do that yet.
19:54brehautmec not true, only the sequence functions
19:54brehautmreynolds: dorun is the answer
19:54brehautmreynolds: you shouldnt be putting side effecting code into a sequence anyway
19:56brehaut(apply the same caveats you would to any other blanket statement to that one too)
19:56mreynoldsbrehaut: 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:56mreynoldsI 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:56brehautmreynolds: first question then: do you care about the result of the pluggin?
19:57mreynoldsbrehaut: At this point, I don't
19:57mreynoldsbrehaut: I'm having a hard time thinking of a case where I would
19:57brehautthen go with no until you discover a case
19:57mec(doseq [f @registered-plugins] (f event))
19:57brehauti would suggest using a doseq
19:57brehautjust like that :)
19:57mreynoldsalright, I'lll try that :)
19:57meclol
19:58brehautsimply because its explicit that it side effecting
19:58mreynoldsI was avoiding it because of the "side-effects" in the docs, but that's actually exactly what I want
19:58mreynoldsheh
19:58mreynoldsThanks for helping me think about that differently, guys
19:58mreynoldsI'll go re-work a bit
19:58brehautno worries
19:58brehautmreynolds: side effects are fine if the program is clear about their scope and effect
19:59mreynoldsbrehaut: 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:59brehautmreynolds: im curious about why you have a non-pure plugin system though; what are youy building?
19:59mreynoldsbrehaut: It's a toy minecraft server, mostly so I can learn clojure more fully
20:00brehautmreynolds: what are the plugins responsible for?
20:00mreynoldsbrehaut: At work, I'll be using clojure and ring to build simple REST servers so others can use them as prototypes.
20:01brehautmreynolds: that should be really straight forward (ring + rest)
20:01mreynoldsbrehaut: Plugins are responsible for various tasks like : *returning portions of the world when clients enter an area, * managing inventory, * etc
20:01mreynoldsbrehaut: Yeah, actually way easier than this problem I have at home
20:01brehautyes
20:01brehautif you are doing simple json stuff its almost just falls out by itself
20:02mreynoldsbrehaut: 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:02mreynoldsbrehaut: 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:03mreynoldsbrehaut: 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:03mreynoldsbrehaut: Yeah, the existing mess is ... messy
20:03brehautmreynolds: why did you chooses an agent for your plugins ?
20:03brehautrather than say an atom
20:04mreynoldsbrehaut: No particular reason. I liked the async portion of agents for management of the plugins.
20:05mreynoldsbrehaut: 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:05brehautthey one interrupt each other in either case
20:05mreynoldsEventually I plan to externalize the events to allow for choosing between in-process and out-of-process messsaging
20:06brehauterr they wont
20:06mreynoldsbrehaut: It's more about behaving really poorly (blowing the stack, heap, etc). The examples I have are simple now, but have similar constraints
20:06mreynoldsbrehaut: For the home server, the world can be mismanaged and eat a ton of memory, etc
20:07mreynoldsbrehaut: But you're right, from a processing standpoint, it won't matter
20:07mreynoldsMy primary concern, at work, will be programmers making bad engineering decisions and needing to contain those
20:09brehautmreynolds: i prefer education to api constraints to solve that problem ;)
20:10mreynoldsbrehaut: That's step 2. First step is proving that they're making bad decisions without allowing them to sink the app :)
20:10mreynoldsI'm new and I don't have a ton of buy-in for the style I'm proposing
20:11mreynoldsI 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:11brehautmreynolds: in my opinion you dont want to straightjacket them
20:11brehautlet them make their own mistakes and learn from it
20:11mreynoldsbrehaut: 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:12mreynoldsbrehaut: 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:13mreynoldsbrehaut: 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:13mreynoldsAnyway, not to rant too much about work :) I appreciate the help.
20:15crowbarIs 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:16znutar_is using java IO classes the idiomatic way to read things from stdin?
20:16brehautznutar_: yes; clojure.java.io provides utilities to do so
20:17brehautznutar_: see also http://clojuredocs.org/quickref/Clojure%20Core
20:18mecznutar_: on the off chance that you're using emacs, reading from slime is buggy
20:25crowbarIs 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:26brehautcrowbar: i have in the past
20:27brehautcrowbar: http://clojars.org/clojureql
20:27crowbarI tried that. Looks like I might have a different problem though.
20:28brehautrunning the latest lein?
20:29crowbarLeiningen 1.5.0 on Java 1.6.0_24 Java HotSpot(TM) 64-Bit Server VM
20:30brehautim out of ideas then sorry
20:30crowbarthanks 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:31brehautnope clojars should just work via maven plumbing
20:31brehautcrowbar: did you post about this on HN today?
20:31crowbarmaybe :)
20:31crowbarsmall world.
20:31brehautnot really :P
20:32brehauthttp://news.ycombinator.com/item?id=2430037 im presuming?
20:32brehauti didnt know what you meant by over-hyped development style
20:32crowbarheh. yep. I've pretty much had a horrible time at every step in the process.
20:33brehauti found that quite surprising; i have had basicly no trouble getting runnign with ring etc
20:33crowbarring actually was easy.
20:33brehautthats part of the magic of it :)
20:33brehautive not really used compojure myself
20:34brehautso i dont know if thats been the source of your issues
20:35crowbarswank 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:35brehautcrowbar may i suggest hopping on #clojureql - you might get help with the specifics there if its not a lein issue
20:35brehautcrowbar: ok i have completely avoided swank
20:36brehautcrowbar: but from what i understand you should ignore every tutorial in the wild and follow the instructions in the README.
20:36brehautcrowbar: the django tutorial is pretty good
20:37crowbarI think I'm having just a general lein issue.
20:37brehautcrowbar: 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:37znutar_brehaut: mec: thanks!
20:40znutar_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:41dnolencrowbar: 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:43brehautenlive is a reason to persevere with clojure for web all by itself
20:48Raynesbrehaut: Man, I'm writing some straight HTML for the first time in forever. :o
20:48brehautRaynes: i do that all the time :P my latest blog post is 4500 words all manually marked up :P
20:49RaynesMy blog posts are usually only slightly marked up.
20:49brehauti often use markdown, but this one has diagrams
20:49brehautand i did them with html and css
21:13jweissis 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:14jweisssyntax quote and unquote splicing almost works
21:14jweissbut it doesn't
21:14jweiss,`{~@[:a b:]}
21:14clojurebotInvalid token: b:
21:14jweiss,`{~@[:a :b]}
21:14clojurebot1
21:17mecwow apparently lazy-seq binds recur :x
21:17dnolenjweiss: don't think that's possible, but I also don't see much benefit.
21:17dnolenmec: ?
21:17mec,(lazy-seq (recur))
21:18clojurebotExecution Timed Out
21:18dnolen,(recur)
21:18clojurebotExecution Timed Out
21:18dnolenmec: nothing to do w/ lazy-seq
21:19mecin my code i've got (fn blah [x] (lazy-seq ... (recur y))) and it says recur expects no args
21:23gtrakthere might be a loop in the ...?
21:23gtrak.(recor)
21:24gtrak.(recur)
21:26dnolenmec: recur on lazy-seq doesn't make sense. lazy-seq computations are more general than recur.
21:27dnolen(fn blah [x] (lazy-seq ... (blah y)))
21:27dnolenmec: ^ is what you want.
21:30meci have to do some extra computation inbetween the lazy-seq bindings
21:31dnolenmec: ? and what stops you from doing that?
21:37mecthats what the recur was for
21:38mechang on i'll gist this
21:39dnolenmec: you can't use recur inside lazy-seq, there's no place to recur to.
21:40mechttps://gist.github.com/912946
21:41brehautmec: yikes!
21:42meclol, 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:43brehautmec :when (identiy new-pos) is the same as :when new-post
21:44mecah right, just blindly changed that from (filter identity)
21:44brehautmec: well also new-pos is always truthy i think; only nil and false are falsy
21:44mecit could be nil if x or y are <= 0
21:45brehaut,(boolean [])
21:45clojurebottrue
21:45dnolenmec: your code works fine for me.
21:45mecya i added the loop, before it was just the fn
21:46brehaut,(boolean [(when (pos? -1) [1]) (when (pos? -1) [-1])])
21:46clojurebottrue
21:46brehaut((juxt identity boolean) [(when (pos? -1) [1]) (when (pos? -1) [-1])])
21:46brehaut,((juxt identity boolean) [(when (pos? -1) [1]) (when (pos? -1) [-1])])
21:46clojurebot[[nil nil] true]
21:46mecdont forget the for pulls the vector apart
21:47brehautah true
21:57meci feel this is overly complicated in general
22:07devng'day all
22:18crowbarARRRggg. Just realized the issue was that I have to disable ipv6 for java to reach the network.
22:18crowbarbecause I removed openjdk and install sun jdk by recommendation of some stupid blog that openjdk breaks clojure.
22:18crowbarAnyway, lein and clojars was not the issue.
22:23amalloymec: you definitely can't recur across the boundary of a lazy-seq. it doesn't make sense
22:24amalloythe good news is, there's not really any reason to want to do so
22:24meci know, i just forgot to add in a loop
22:26amalloymec: 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:26amalloyi wonder whether having a loop/recur inside a lazy-loop/lazy-recur makes things less readable
22:27mecits that or get rid of the lazy and loop, but have to carry around a results vector
22:28amalloymec: not really. you could drop the inner loop entirely
22:29amalloy(if (= 0 x y) (cons result-level (routes* queue-left)) (routes* (into queue-left ...)))
22:30amalloysince 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:33mecoh? i can do this immediatly in my code?
22:34amalloyindeed, the snippet i pasted should "just work"
22:34mecwow, so the lazy-seq just keeps calling that until it gets a value? no chance of a stack overflow?
22:34amalloymec: that's the magic of lazy seqs
22:35amalloyit's effectively using the caller's stack frame as a trampoline
22:35mechuh never knew that, i thought it always had to return a value
22:36amalloy&((fn make-zero [x] (if (zero? x) [0] (make-zero (dec x)))) 10000)
22:36sexpbotjava.lang.StackOverflowError
22:36amalloyhm
22:36amalloyhah forgot lazy-seq: ##((fn make-zero [x] (lazy-seq (if (zero? x) [0] (make-zero (dec x))))) 10000)
22:36sexpbot⟹ (0)
22:36amalloyan apt demonstration of the fact that it works, i guess
22:36mecvery true
22:37mecso how does this work?
22:37amalloymec: 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:37amalloythe caller sees it, notes that it's a lazy-seq, and asks it to force itself
22:38amalloya thunk is immediately returned, which is forced...
22:38amalloyglossing over details there, but that's the general flow
22:43mectheres actually a couple places I can apply that little bit of knowledge to
22:46mecthey 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:47amalloymec: loop/recur is surely faster. avoids creating and destroying stack frames
22:48mecah i see
22:51meclooks like they are near identical in speed
22:53zakwilsonI'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:54mecit could just be blocking on read and since its always sitting there just seems to take the most time
22:54mecbut that is just completely a guess
22:59zakwilsonDoesn'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:05mecamalloy: its weird but even when a lot of computation happens in the loop, the version without it is equal or faster
23:07amalloymec: 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:08zakwilsonAt idle, it spends all its time doing java.lang.Thread.sleep(), which is expected.
23:09mecamalloy: thats instead of using route* right?
23:09amalloyyeah
23:09mecok let me try it
23:17mecamalloy: i like it
23:17amalloycool, thanks
23:18mecdeffinitly beats having to put the args at the ass end of the fn
23:22amalloymec: yeah, that readability improvement was a big motivator
23:24mecany other lazy tricks you'd like to share? :D
23:25amalloymec: nah, lazy-loop is a pretty recent development for me. feel free to steal whatever you want from amalloy-utils though
23:58mecin emacs is there a way to auto indent 2 spaces anything with the form (fn [] instead of indenting to the leveling of the [