#clojure logs

2009-02-27

00:13erohtarchouser: you there?
02:24hiredmanmy sentiments exactly
02:24hiredmanclojurebot: translate from jp #?4?????????,?????????????????????????
02:26hiredmanclojurebot: translate from ja #?4?????????,?????????????????????????
02:26clojurebot# 4 I'd like to get one, and it would be prudent to think out collection
02:27hiredmanclojurebot: translate from ja ?????
02:27clojurebotNow
03:50Lau_of_DKHey guys
03:53cmvkki have these two concurrent functions, one is hand rolled and the other uses pmap. they both run at almost exactly the same speed (one's 4% slower), but only the pmap version pegs both cores.
03:53cmvkkwhy wouldn't (doseq [cur-agent list-of-agents] (send-off cur-agent a-long-function)) run concurrently?
04:16Lau_of_DK(doc send-off)
04:16clojurebotDispatch a potentially blocking action to an agent. Returns the agent immediately. Subsequently, in a separate thread, the state of the agent will be set to the value of: (apply action-fn state-of-agent args); arglists ([a f & args])
04:50kotarakThe docstring discussion will also never die.......
04:51cmvkkit appears that i'm send-offing 4 agents at once, but three of them always wait for the first one to finish.
04:59cmvkkaha! i was using an incrementing atom (swap! counter inc) to make sure they didn't step on each other's toes, but apparently you can't do that from simultaneous dispatches.
05:03Lau_of_DKTry commute instead
05:03Lau_of_DKFor a counter it'll work just fine
05:07cmvkkactually i really only needed to assign each agent a number then increment by (+ cur-num *num-agents*).
05:07cmvkkone of those 'should have used a pencil' scenarios...
05:12Lau_of_DKk
06:12djpowellHmm, strings are seqable, but stringbuffers aren't. It might make more sense to define StringSeq to work over any CharSequence
06:13leafwdjpowell: time to submit an enhancement proposal.
06:25leafwthese tweets are out of place here, IMO.
06:27HolcxjoI agree -- maybe we need a #clojure-social channel for these bulk messages?
06:31leafwHolcxjo: do you know who is in charge of the clojurebot? Just suggest it to him if you do.
06:32HolcxjoNope.
06:32Holcxjoclojurebot: who is your master?
06:32clojurebotGabh mo leithsc�al?
06:32Holcxjo:-)
06:37Hunclojurebot: take me to your leader
06:37clojurebotHuh?
06:40leafwclojurebot: bdfl
06:40clojurebotI don't understand.
06:52leafw,(doc find-doc)
06:52clojurebot"([re-string-or-pattern]); Prints documentation for any var whose documentation or name contains a match for re-string-or-pattern"
07:30AWizzArdclojurebot: max people
07:30clojurebotmax people is 149
07:35kotarak_leafw: isn't it hiredman?
07:40leafwkotarak_: sounds familiar; perhaps yes
08:05clojurebotsvn rev 1311; fix print-method for objects with :type meta but no print-method, patch from Konrad Hinsen
08:39MarkVolkmannIs it correct to say that each loaded function is represented by an AFn object in memory?
08:55kotarak_MarkVolkmann: I think macros are simply functions with :macro true in their metadata.
08:55kotarak_Correction: Vars
08:56kotarak_You can even do (defmulti bla ....) and then a (.setMacro #'bla).
08:56kotarak_And you get a multimacro.
10:30HolcxjoIs there a form of let where the value can already make use of the name to be defined? I.e. something so that (let [a (cons 1 (map inc a))] (take 4 a)) works?
10:31HolcxjoOr do I have to model this with a loop or something?
10:41ChouserHolcxjo: interesting. the most common need for that is a fn referring to itself from inside its body. that's supported.
10:41Chouserotherwise you'll need some kind of reference type, a global var being the most common.
10:42ChouserIf you don't like the global, you can use with-local-vars to get a local var, or use an atom or ref stored in a local.
10:44HolcxjoChouser: I don't like the idea of an atom or ref or anything -- this is a fully functional algorithm...
10:44HolcxjoI'll need to learn about with-local-vars
10:45Chouseror use a different construct for the body of the expression. 'iterate' would work in your (I assume simplified) example.
10:46Chouser,(let [a (atom nil)] (reset! a (lazy-seq (cons 1 (map inc @a)))) (take 4 @a))
10:46clojurebot(1 2 3 4)
10:48rhickeylooks like someone wants letrec again
10:49Holcxjo:-) Pretty please?
10:50rhickeyChouser: looked at :let, wondering if there might be some subtleties about order now :when guard :let [x something-expensive]
10:50Chouserrhickey: yes
10:50Chouser:-)
10:50rhickey:when and :while order themselves
10:50rhickeylooks like :let always first in your patch?
10:51ChouserIs it really impossible for someone to want to use :when to guard and expensive :while?
10:51Chouseryes, :let comes first in my patch.
10:51Chouser"an expensive"
10:52HolcxjoChouse: Couldn't that possibly cause exceptions? for [x natural-number :when (pos? x) :let [inv (/ 1 x)]
10:52HolcxjoI.e. the let may rely on the guard to be true to be valid
10:53ChouserHolcxjo: I think that's what rhickey is noting, yes.
10:53HolcxjoChouser: Well he said "expensive". I meant "failing"
10:54Chouserbut I wasn't sure if that was unacceptible, since it seems possible that the existing :when and :while have a similar ordering issue.
10:58Chouser(for [a (range -2 5) :when (not= a 0) :while (> (Math/abs (/ 1.0 a)) 1/3)] a)
10:58Chouseror something.
10:59ChouserI imagine allowing :when and :while to guard each other and :let would be possible, but would take a bit of work.
11:10HolcxjoSo, back to my problem :-)
11:10HolcxjoHow does one canonically and concicely represent a problem where I want to do something like (let [result (cons start-value (map some-function result other-seq1 ...))] result)
11:10HolcxjoDo I need to pollute the namespace with a global name to do that?
11:12Chouserdid I fail to answer that? I think I listed the possible routes to solving that.
11:13HolcxjoSorry, so the canonical way if via an atom? Yikes. :-(
11:15HolcxjoMy apologies -- I assumes that was just a quick hack while thinking about a cleaner solution... I'll give that a try I guess
11:15Chouserwell, your options are: global var, local reference type (var, atom, ref), or adjust your expression: somehow use a named fn or use something that can refer to itself but not by name
11:16Chouserfor the example you posted, 'iterate' would work. It might not in your real world case, but perhaps something similar could be done.
11:17Chouserif nothing like that works, perhaps a self-recursive function would work, since they can have a private name for their own body:
11:17Chouser,(take 5 ((fn foo [] (lazy-seq (cons 1 (foo))))))
11:17clojurebot(1 1 1 1 1)
11:18Chouserfailing that, and not wanting to touch a namespace global, 'atom' is probably the simplest reference type.
11:18kotarakIsn't that a candidate for a lazy-seq? (let [make-seq (fn make-seq [start-value other-seq] (lazy-seq (cons start-value (make-seq (compute-new start-value (first other-seq)) (rest other-seq))))) a (make-seq start-value other-seq)] (take 4 a)), not tested and kotarak is absolutely unclear about the new lazy-seq stuff.
11:18Chousernote it's mutated exactly once, so it's not as if the mutation is getting into your algorithm.
11:19HolcxjoChouser: Thanks. That was a very elaborate an complete answer
11:19ChouserHolcxjo: I realize it's not letrec, but it's what we've got right now
11:19HolcxjoSo, is there a reason for the absence of letrec?
11:20Chouseryou'd have to take that up with rhickey. it's not something I've thought about, but I'm sure he has.
11:21Chouserkotarak: possibly something like that, yes, leveraging the private name feature of fn.
11:22rhickeyhttp://code.google.com/p/clojure/issues/detail?id=89
11:24Chouserrhickey: would it not be called 'let'?
11:24Holcxjorhickey: Thanks. I added my star to that
11:24ChouserI guess that would prevent using let to repeatedly replace the same local name.
11:25kotarakargh :(
11:25rhickeyChouser: no
11:33rhickeyWhere is Holcxjo's original problem? (came in late)
11:36Chouser(let [a (cons 1 (map inc a))] (take 4 a))
11:36rhickeyChouser: thanks
11:38rhickeywould become: (letrec [a (lazy-seq (cons 1 (map inc a)))]
11:38Chouserand not 'let' because it would be a breaking change?
11:40Holcxjorhickey: (let [result (cons start-value (map some-function result other-seq1 other-seq2 ...))] result)
11:40HolcxjoSo basically a simple iterate doesn't work as I need other sequences as well in there
11:41rhickeymixing let and letrec is not normally done in non-lazy languages letrec/labels/let rec(ML)
11:43rhickeye.g. simply (letrec [a (cons 1 (map inc a))] (take 4 a)) wouldn't work because a is undefined when used in the initialization call to map
11:44kotarak,(let [make-seq (fn make-seq [start-value] (lazy-seq (cons start-value (make-seq (inc start-value))))) a (make-seq 1)] (take 4 a))
11:44clojurebot(1 2 3 4)
11:45kotarakHolcxjo: so lazy-seq may help you now, until letrec is available.
11:45Holcxjokotarak: Thanks -- need to look into that to understand this solution
11:47kotarakHolcxjo: see also my previous example how to incorporate other-seq etc.
11:54Holcxjokotarak: Thanks: I missed that example
11:55kotarakHolcxjo: it's kind of manual map
11:59drewrrhickey: Is (if (first s) s nil) an acceptable seq/nil implementation? That's essentially the patch I submitted.
12:03Chouserdrewr: which patch is that, if I may ask?
12:04drewrChouser: http://code.google.com/p/clojure/issues/detail?id=87
12:04Chouserah, searching for "drew" was getting me nowhere.
12:04Chouser:-)
12:05drewrI'm surprised it doesn't put a name in there for gmail addresses.
12:07ChouserI think (if (seq s) s nil) or perhaps just (seq s) might be more generally correct, but I'm not sure if there's a specific problem with what you've got.
12:08drewrGood call. (seq s) is probably better.
12:08drewrbrb
12:14cgrandHolcxjo: you can hide the atom trick into a macro, that's what seq-utils/rec-seq does: (let [a (seq-utils/rec-seq a (cons 1 (map inc a)))] (take 4 a))
12:19Mechow come let uses a vector to represent bindings instead of a map? is it just the aesthetic of the square vs curley or is there a reason?
12:21kotarakMec: locals are serial: (let [a (initial-step) b (next-step a) c (another-step a b)] (use a b c here)). You loose this with a map.
12:24Holcxjocgrand: Thanks -- that looks neater; I'll try that
12:24Meckotarak: makes sense i guess, thanks
12:36drewrLooks like seq is slightly faster than first too.
13:15clojurebotsvn rev 1312; updated add-watch doc
13:26erohtarchouser: u there?
13:26Chouseryep
13:26erohtarchouser: so i was thinking about our conversation yesterday about vars
13:27erohtarchouser: so vars in clojure arent the same as dynamically scoped variables in common lisp?
13:27ChouserI don't know CL well enough to say for sure, but my understanding is that they're pretty much equivalent.
13:28Chousera possible difference being how threads interact with them -- not sure what CL does there.
13:28erohtarchouser: the thing is... in common lisp, if i bing var-a to x, any thing down the call stack will see x...
13:30erohtarchouser: in clojure, it doesnt seem to behave like a closure... (laziness, during realization) is that correct? if var-a was bound to y elsewhere, realization of the old lazy stuff would now see y
13:30erohtarchouser: is that right?
13:31ChouserCL doesn't do lazy seqs, right? so lets ignore that for now
13:31erohtarchouser: ok...
13:31Chouserlet's just look at how a closure works.
13:32gnuvinceIs there a better tutorial about Swing than the Trail on on Sun's site?
13:32erohtarchouser: i think i understand how a closure works, but when a closure is going to be evaluated lazily... what happens to a var that has since been rebound?
13:33Chouser(def var-a 2), (let [add (binding [var-a 5] (fn [n] (+ var-a n)))] (add 3))
13:33Chouserok, here's a little example that I would expect to work the same if translated to CL
13:34Chouservar-a has a root binding of 2.
13:34erohtarchouser: that should eval to 8, yes?
13:34Chouserno
13:34erohtarchouser: hmmm
13:34Chouserwithin the dynamic scope of the binding, a closure is created that refers to var-a
13:35erohtarchouser: ok... and that is 5?
13:35Chousukenah, it's var-a
13:35erohtaroh
13:35Chouserat the moment the closure is created, var-a has a thread-local binding of 5, but that doesn't really matter because nothing is asking for var-a's *value*, just grabbing var-a itself.
13:36erohtari see... ok...
13:36Chouserso that closure is returned to outside the binding, and named 'add'
13:37ChousukeI guess it's a bit surprising though.
13:37Chouserand what does the closure have bundled inside? it knows it wants one arg n, and it has references to the vars var-a and +
13:37erohtarand it dynamically uses the value 2, for var-a when it needs it?
13:37Chouserright
13:37erohtararent closures supposed to capture their environment?
13:38Chousertheir lexical environment, yes.
13:38erohtarnot the values?
13:39Chouserwhich is why this works: (def var-a 2), (let [m 7, add (binding [var-a 5] (fn [] (+ var-a m)))] (add))
13:39Chouserhm, not that's not quite right, since m is still available when 'add' is called. But anyway, it wouldn't have to be.
13:40erohtarthinking about this
13:40Chouserif you think about how dynamic vars are used in clojure.core, you'll see it must be this way.
13:40Chouserlet's look at *in*
13:40Chouserer, *out*
13:40Chousuke,(let [x 1 add (fn [] (+ 4 x))] [(binding [x 2] (add)) (binding [+ -] (add))])
13:40clojurebotjava.lang.Exception: Unable to resolve var: x in this context
13:40Chousukehmm
13:41erohtarok - talking about *out* - is that the std-out ?
13:41Chousersomewhere there's something like (def *out* System/out)
13:41Chouserright
13:41Chousuke,(let [x 1] (let [add (fn [] (+ 4 x))] [(binding [x 2] (add)) (binding [+ -] (add))]))
13:41erohtarright
13:41clojurebotjava.lang.Exception: Unable to resolve var: x in this context
13:41Chouserthat's the root binding of *out*
13:42erohtarok, with u so far
13:42Chousukehmm, I guess binding let-bound variables does not work
13:42Chouserthen you've got functions like prn that use *out*
13:42erohtaryes... i think they need to be vars
13:42erohtarright
13:42kotaraklet-bound locals are not Vars
13:43Chousukehmm
13:43Chousuke,(let [x 1] #'x)
13:43clojurebotjava.lang.Exception: Unable to resolve var: x in this context
13:43Chouserwe can pretend prn is defined something like (defn prn [& args] (.write *out* args))
13:43erohtarwhen u create a lazy something, that uses prn, what happens?
13:43Chousukeindeed.
13:44Chousernow, if prn took the value of the *out* when it was defined, there would be no way to get prn to write to any other stream -- it would always use the root binding, since that's what was in play when prn was defined.
13:44Chouserbut that's not how it works.
13:44Chouserprn has a reference to the Var *out*, not its value.
13:44erohtarso something like - (map #(prn %) [1 2 3])
13:44erohtarchouser: i completely agree
13:45Chouserso instead, prn will use the dynamic value of *out* when you call it.
13:45erohtarchouser: hmmm
13:45Chouser,(with-out-str (prn 5 10))
13:45clojurebot"5 10\n"
13:45Chousergot it?
13:45erohtari do
13:45erohtarim thinking about my confusion - and trying to figure out the question to ask next
13:46erohtarso lets take my example -
13:47erohtar(map #(prn %) [1 2 3])
13:47erohtarnow, somewhere else, i rebind *out* to str... and in there, if i use the above object, will it also use the new binding?
13:47erohtarit will...
13:48erohtari think im getting it now
13:49erohtarok - final thought -
13:49Chouser(def q (map #(prn %) [1 2 3])), (with-out-str (doall q))
13:50Chouserso yes, even though you created the lazy seq and closure outside the with-out-str, since its not computed or realized until the doall which is within the with-out-str, all those prn's will use the binding provided by with-out-str
13:50erohtargot it...
13:50erohtarso my final thought - what if instead of *out* we're talking about a connection to a database... bad use of vars, right?
13:51Chousernow lazy seqs can be a bit tricky because they cache their results and can effectively contain multiple closures.
13:51Chouserhmm....
13:51erohtarif i read from a db a list of objects using a var that holds database config.... and then i rebind the config to write into another database
13:51Chouserif you're going to open a connection to a database, do a batch of work in a single thread on it, and then close the connection -- then that would be a fine use.
13:52erohtarsince the initial read may be lazy... when it realizes... it will 'read from the wrong place'"?
13:52Chouserright
13:53Chouserbasically you want to be very careful about passing closures (and therefore lazy seqs) past 'binding' boundaries.
13:53erohtarchouser: on that thought - what i did was, i read from a db, and to write into the other, i created agents, binding the new db config in each
13:53erohtarchouser: it didnt work...
13:54erohtarchouser: ok... im beginning to understand ...
13:54erohtari need to rethink what im doing
13:54erohtarand avoid using vars for some of this stuff, since im doing a lot of agent related stuff
13:55Chouseryes, I'd recommend trying to have the behavior of as much of your code as possible depend only on the args passed directly in.
13:55erohtarchouser: this whole mess started when i wanted to avoid passing db-config around everywhere
13:55Chouserthis is better for testing, reasoning about behavior, easier to work with threads, closures, laziness, etc.
13:55Chouserheh, yeah.
13:56erohtaryup - i hear you
13:56Chouserwell, another thing that may be helpful -- just guessing since I haven't seen your code...
13:56erohtarthanks a ton for your time - ur incredibly helpful
13:56erohtarok?
13:56Chouserwould be to try to keep as much of your code purely functional as possible.
13:56erohtaryes - i understand
13:57Chouserso avoid writing a function that takes some args, does some computation, and then writes to a db. Instead, have a fn that takes args, does computation, returns result.
13:57Chouserthen perhaps you don't have to pass in db config at all -- whoever calls this fn can to the db write itself.
13:57erohtari think it mostly is... except for this stuff... where i ended up inadvertently depending on "global" db-config
13:57erohtarwell, this is a persistence layer
13:58erohtari take an object in, break it up etc., and put it into hbase
13:58erohtarthe code is open-sourece... would u like to see?
13:58Chouserhm, sure. I may need to ramp up on hbase soon.
13:58erohtarhttp://github.com/amitrathore/capjure/blob/b939a7038ebb4aed0d068d6e86291cc881ecf72b/src/org/rathore/amit/capjure.clj
13:59erohtarits kind a messy - learning clojure and hbase while doing this...
13:59Chouser:-)
14:00Chousukeerohtar: first thought: use some newlines.
14:00danlarkinNoooooooooooo -jure
14:00erohtardanlarkin: haha - u've told me that already
14:00Chouserdanlarkin: hey, at least he's got a name
14:00Chousukeerohtar: one newline after each def/defn would make it a lot nicer :)
14:00danlarkinerohtar, Chouser: :)
14:01erohtarok - more newlines, check
14:01Chousukewell, the def group is fine I guess.
14:02Chousukebut (defn foo) (defn bar) without an empty line in the middle is a bit weird
14:02erohtarok - those were sort of just quick utility functions... but i'll put newlines
14:03Chousukenewlines never hurt anyone
14:03Chousererohtar: this is what you get for posting code. unsolicited advice. :-)
14:03erohtarhaha
14:03erohtarits fine - maybe i'll learn something too :)
14:03Chouserbut while we're at it -- I much prefer to have the code arranged so that 'declare' is only needed in mutually-recusive situations.
14:04Chouserthough others may disagree with me
14:04erohtarright - i struggled with that one - cause i dont like to have to order the functions in "reverse"
14:05erohtarsee - capjure-insert is the only one that most people will call
14:05Chousukeerohtar: you could add more newlines and some kind of "headlines" for sections of code
14:05erohtaru bind the config stuff - *hbase-master* and *primary-keys-config* - and then u call capjure-insert with the params
14:05Chousukeso people can easily skip the helper function blocks
14:05erohtarmost of the remaining functions are functional
14:06erohtaronly the ones dealing with hbase have (obvious) side-effects
14:06erohtarand it works fine... and its in production too... ran into issues trying to use TWO hbase configs (to move data between them)
14:06Chousukethat's a lot of functions for one namespace too, though :)
14:07ChouserI really don't think more namespaces would be better.
14:07Chousukeif possible maybe it'd make sense to put the "side-effecting" functions (that deal with hbase) in a separate file or namespace?
14:07erohtarcause lazy lists of data from one hbase, seem to be getting messed up when i rebind the config to start writing into the other hbase
14:08erohtardo u know what i mean? (trying to get discussion back to lazy closures and bindings :) )
14:08Chousukeah
14:08Chousukeright, I can see why that happens :)
14:08Chousukethe laziness gets evaluated in the context of the new hbase.
14:08erohtarwell, im only starting to see it :) thanks to u guys...
14:08erohtaryea
14:08erohtardrove me crazy
14:09erohtarand i did all this only so i wouldnt need to pass the db config around all the functions
14:09erohtarlike u said, there are a lot of them...
14:09Chousukewhich means you will have to move away from using global vars for config and instead create something you explicitly pass around to the functions.
14:09erohtarso now what... ? pass the config around everywhere?
14:10Chousukemaybe only to a few core functions.
14:10erohtaryea
14:10Chousukewhich then would bind the dynamic vars.
14:11erohtarwell, if i pass it in, i dont need dynamic vars, rite
14:11Chouseror don't use lazy seqs
14:11Chouseruse doall or stuff them in a vector first
14:11erohtarhmmm
14:11cemerickuk, the ILC registration site doesn't allow one to register more than one person at a time
14:11erohtarthat might be one solution
14:11Chousukeright, if they are side-effecting that might be better.
14:12Chousercemerick: how many people are you?
14:12Chousukethough maybe not memory-efficient :/
14:12erohtaryea
14:12cemerickChouser: oddly enough, 2 ;-)
14:12Chouser:-)
14:12erohtari think i will get rid of the dynamic vars
14:12Chousukeit's a shame though
14:12erohtarwhat is the pattern for this kind of 'static' config being passed around?
14:12Chousukethey make the code much easier to write :P
14:13cemerickI may end up sticking around through Tuesday -- Sussman's talk on Tuesday sounds fantastic
14:13ChousukeI wonder if there's a better solution
14:13Chousukesome way to "bind" the current config to when the lazy-seq is first created
14:13erohtarin typical OO, u can create an instance variable to hold the config - i wonder if in clojure u can create something like that... and since its immutable, it should be fine, rite?
14:14Chouseryes
14:14Chousukemaybe do (let [config *global*] (return-some-lazy-seq-qith config))?
14:14erohtarbut there is no way to do that, rite?
14:14Chousukewould that fix the value?
14:14erohtaryea
14:14Chouserstuff all your config into a map, and pass that single thing into functions that need to use it
14:14erohtari thought of doing something like that... but other functions couldnt access those values...
14:15erohtari thought of simulating an 'immutable object oriented system' -
14:15erohtarlike how u do in javascript... but immutable
14:15ChousukeI did in clojurebot so that I pass a map of config stuff around with every function
14:15erohtarreturn a closure with the vars bound with a let... and then closures for all the other functions also
14:16Chousukeit's a bit tedious though :/
14:16erohtari dunno if im being clear
14:16erohtarvery tedious
14:16erohtarmacros can help
14:16erohtaressentially what id be doing is creating an immutable OO system
14:16erohtarsomething like that
14:16erohtardoes that make sense?
14:16Chousukeerohtar: but your problem is only with lazy seqs right?
14:16erohtarlazy seqs and dynamic vars
14:17Chousukeerohtar: don't you only need to fixate the config when returning a seq
14:17erohtarthe interplay
14:17erohtaryes
14:17Chousererohtar: clojure.zip does something like that
14:17erohtarchouser: like what?
14:18Chousereach node is a object with a several functions attached as metadata
14:18erohtarchouser: ah, i see
14:18erohtargot it
14:18Chousermost of the api fns are like (children my-node), where children calls fns from my-node's metadata, passing in my-node
14:19erohtari see -
14:19erohtarthats rather cool - so u can basically have my-node equivalent contain the config data
14:20Chousersure
14:20erohtaralright folks, thanks a lot for this conversation - im going to experiment and see how to get this done with the least amount of work :D
14:20Chouserthe only reason zip nodes have fns in metadata is so it can be polymorphic.
14:20erohtaryes- makes sense
14:21erohtar(then everyone can tell me how my code sucks :) )
14:21Chouserif you're going to only have one kind of db config (seems likely) then you don't need the metadata piece.
14:21erohtaryes - just need to take care of the fact that the config will be rebound... so just closures that capture the config, and the functions that use it
14:21erohtarsomething like that
14:41durka42oh dear
14:41durka42that post on ACP must be before lazy
14:41durka42it's confusing me because it calls rest and has parameters named next
14:42Chousukeheh
14:42ChousukeI wonder what the point of the runnable function is
14:43Chousukedid the author forget that clojure fns implement runnable
14:43Chousukethe use of cons seems weird too :)
14:44Chousukemaybe it makes more sense to someone with a CL background, but I'd just use a literal vector :P
14:45kotarakliterals have their gotchas, too. ;)
14:45ChousukeI guess
14:46Chousukebut (apply foo (cons bar zonk)) just looks unclojurey :)
14:49kotarakoerk
14:50Chousukeyeah, it's pretty rare
14:51rhickey(apply foo (cons bar zonk)) ==> (apply foo bar zonk)
14:52Chousukeoh, right.
14:52Chousukeno need for a vector either.
14:53kotarakwell, cons will be revived with lazy-seq, I fancy.
14:56kotarakthe author probably doesn't know that between the sequence and the function in apply, there might be other arguments. I came across this misunderstanding several times now.
14:58tashafa,(. "test" (replaceAll #"e" "a"))
14:58clojurebotjava.lang.ClassCastException: java.util.regex.Pattern cannot be cast to java.lang.String
14:58tashafahmm.. what im i doing wrong?
14:58tashafa,(. "test" (replace "e" "a"))
14:58clojurebot"tast"
14:59tashafa,(. "test" (replaceAll "e" "a"))
14:59clojurebot"tast"
14:59tashafa,(. "test" (replaceAll #"e|s" "a"))
14:59clojurebotjava.lang.ClassCastException: java.util.regex.Pattern cannot be cast to java.lang.String
15:00Mecanyone know the etymology of clojure
15:00tashafadoesn't "replaceAll " take a regexp pattern as its first argument?
15:00Chousertashafa: no, it takes a string
15:01kotarak,(replaceAll "test" "e|s" "a")
15:01clojurebotjava.lang.Exception: Unable to resolve symbol: replaceAll in this context
15:01kotarak,(.replaceAll "test" "e|s" "a")
15:01clojurebot"taat"
15:01Chouserso sad
15:01Chouser,(.replaceAll "test" (str #"e|s") "a")
15:01kotaraksad?
15:01clojurebot"taat"
15:02MarkVolkmannWhat's the best/most idiomatic way to return a non-lazy map from a function when that function obtains a lazy map by calling some other function?
15:02MarkVolkmannThis is related to some database code.
15:02Chouserso sad that .replaceAll takes a regex as a string instead of as a regex.
15:02kotarakChouser: the glories of interface design....
15:02tashafaah ...thanks guys
15:03MarkVolkmannThe result set is a lazy map. I want to return it, but when this function exits, the ResultSet will be closed and I won't be able to get to the ResultSet anymore.
15:03kotarakMarkVolkmann: I suppose you mean (map ....) by "map". I would thing doall.
15:03Chouser"lazy map" isn't the right term. map returns a lazy seq
15:03tashafa,(. "test" (replaceAll "e|s" "a"))
15:03clojurebot"taat"
15:03MarkVolkmannOh right ... a lazy seq of MapEntry object.
15:03kotarakThere is a lazy-map though. *commercialonair*
15:04Chousera seq of mapentry objects? you want to put them in a hash-map perhaps?
15:05Chouserin general you can use doall to realize a lazy seq so it's no longer lazy, or use vec to create a non-lazy vector.
15:05MarkVolkmannGot it! Returning (doall rs) did the trick.
15:06ChouserMec: http://groups.google.com/group/clojure/msg/766b75baa7987850
15:11Mecah hah, thanks. i'd guess that clojure has closures then?
15:11Chouserindeed it does
15:26MarkVolkmannI think you have to get to the point that you're convinced about the benefit of code and data having the same syntax.
15:26MarkVolkmannSomeone posted the URL of an article that addresses this. Just read it last night.
15:27MarkVolkmannhttp://www.defmacro.org/ramblings/lisp.html
15:27pjstadighttp://paul.stadig.name/2009/02/clojure-terracotta-yeah-baby.html
15:28MarkVolkmannIt supports the use of parens in Lisp by stressing the advantages of being able to easily write code that generates code.
15:28pjstadigi wrote up my experiment with integrating Clojure and Terracotta
15:28rhickeypjstadig: just read it - fun!
15:30pjstadigyeah it was fun
15:30pjstadigthanks for a great language
15:33rhickeypjstadig: you're welcome!
15:35Mecis a trailing . a special form or a macro?
15:39kotarakMec: A trailing to dot is a synonym for new: (some.Class.) <=> (new some.Class)
15:39kotarakMec: leading dot is for methods: (.method some-object) <=> (. some-object method)
15:39kotarakMec: and / is for static members: some.Class/STATIC_CONSTANT
15:40kotarak,(macroexpand-1 '(String. "Hello"))
15:40clojurebot(new String "Hello")
15:40WizardofWestmarcand don't forget the ever fun $ for internal classes
15:40WizardofWestmarchad fun w/that last night before Chouser reminded me to use it
15:41WizardofWestmarc"why the hell can't I access this enum?" "oh just do *blahblah full qualified path*.classname$subclassname/enumval
15:41WizardofWestmarc*lights go on and everything just works*
15:44kotarakAlso Class. and .method are treated specially in syntax-quote.
15:44kotarak,`(String.)
15:44clojurebot(java.lang.String.)
15:44kotarak,`(.method obj)
15:44clojurebot(.method sandbox/obj)
15:44cp2i have a string that i want to coerce into a map. its formatted as "key\value\key\value....". obviously, i split by \ to get each component. whats a quick/decent way to use the evenly indexed elements in the resulting array as the keys parameter for zipmap, and likewise with the oddly indexed values?
15:45kotarakcp2: why not simply (apply hash-map splitted-things)?
15:45leafwcp2: get even into one list, odd into another, then zipmap
15:45cp2leafw yes, i know, but i was wondering if there was a better way
15:45cp2kotarak ok, ill see
15:46hiredman,(apply hash-map (.split "foo\bar\bleep\bloop" "\"))
15:46clojurebotEOF while reading string
15:46cp2they need to be escaped
15:46cp2\\
15:46hiredman,(apply hash-map (.split "foo\bar\\bleep\\bloop" "\\"))
15:46clojurebotjava.util.regex.PatternSyntaxException: Unexpected internal error near index 1 \ ^
15:46cp2yeah
15:46cp2i got the same thing
15:46hiredman,(apply hash-map (.split "foo\bar\\bleep\\bloop" "\\\\"))
15:46clojurebotjava.lang.IllegalArgumentException: No value supplied for key: bloop
15:46hiredmananyway
15:47kotarak,(apply hash-map (.split "foo\\bar\\bleep\\bloop" "\\\\"))
15:47clojurebot{"foo" "bar", "bleep" "bloop"}
15:47cp2oh right
15:47cp2regexps are funky in java
15:47cp2double escaping, etc
15:47cp2thanks
15:47leafwcool -- learnt something :)
15:49hiredmannah, the funkiness is because those are not actaully regexs
15:49hiredmanthose are strings that get turned into regexs
15:49cp2hiredman, String.split actually does take a regexp
15:49cp2well, yes
15:49cp2you are right, i should have let you finish typing :)
15:56cp2ah, one more bit onto my previous question
15:57cp2actually, nevermind
15:59cemerickpjstadig: nice writeup
16:00pjstadigthanks
16:00WizardofWestmarchaven't had a chance to read it but I plan to later. Terracota looks interesting as hell, and mixed with Clojure? Mmmm
16:01pjstadigyeah i think its a really compelling combo
16:01pjstadigand of course the only production clojure app (that I know of) supposedly uses Terracotta
16:02WizardofWestmarc*nods*
16:02WizardofWestmarcIt's stuff like Terracotta, and on my end Smack, which really make me appreciate the choice of putting Clojure on the JVM
16:02pjstadigit was definitely a brilliant move
16:03gnuvinceWizardofWestmarc: Smack?
16:03gnuvinceClojure made me like the JVM
16:03cemerickis the appeal of Terracotta the semi-unlimited memory potential?
16:03gnuvinceNow I just need to learn how to use Swing :-/
16:03WizardofWestmarcgnuvince: It's an xmpp client library
16:04cemerickvs. messaging-oriented architectures, I should say
16:04WizardofWestmarcsetting up a web app w/processing backend written in clojure
16:04WizardofWestmarcgoing to use xmpp and a lightweight server (openfire) to inform the backend when it has work to do
16:05WizardofWestmarctook me a while to get it all figured out but finally got all the clojure code working last night
16:06pjstadigcemerick: i think one of the appeals is removing the ORM impedance mismatch
16:07cemerickpjstadig: so there's a whole-cluster-JVM persistence mechanism available?
16:08pjstadignot sure what you mean...terracotta is just that
16:09pjstadigit's not only pitched to replace your database
16:09pjstadigone use case (on their site) is to store temporary data in terracotta
16:09pjstadiglike if you have a wizard interface with stages of completion
16:09pjstadigor there example is an exam that someone takes
16:10pjstadigonly stuff it in your DB when it's complete
16:11cemerickthey've clarified a lot of things on their site since the last time I was there. Just read http://terracotta.org/web/display/orgsite/Kill+Your+Database
16:11cemerickmy last impression was that it was only in-memory clustering
16:12pjstadigthere's in memory and a permanent store mode that commits to disk and maintains state between restarting Terracotta
16:12pjstadigi don't know the history...maybe it wasn't always that way
16:14cemerickjeez, if that actually works, that'd be outrageous on a number of fronts.
16:15WizardofWestmarccemerick: exactly!
16:16WizardofWestmarcand the Terracotta guys are even interested in clojure, so they should be friendly in helping with any problems run into on tying it all together to boot.
16:16pjstadigwhen I signed up at the terracotta site i was contacted by a sales person
16:16pjstadigi responded and told him i was just investigating and sent a line to my blog article
16:17pjstadighe said he forwarded it to their dev team, and they like to hear about cool integrations like this
16:18WizardofWestmarchm, didn't know there was a terracotta book
16:18WizardofWestmarcwill have to remember that for when I am ready to start playing with it.
16:18cemerickwe're using jms right now (openMQ), relatively happily, tho. I wonder how applicable that kind of approach is.
16:18pjstadigi think terracotta has its own niche
16:19pjstadigthey're not necessarily trying to replace your database or messaging system
16:20Chouserpjstadig: I think it would be a relatively trivial use of gen-class to hold Var roots
16:20Chousernice writeup, btw, thanks.
16:21pjstadigit would be interesting to have an example of that
16:21cemerickI'll definitely have to take a look at it.
16:21pjstadigmaybe you could fork my github
16:21pjstadigor maybe i'll play with it
16:21Chouserpjstadig: ok, I may look at that tonight.
16:21Chouserapparently I need to get into this whole distributed server thing.
16:22Chouserterracotta, hbase, hadoop, mongodb, and such
16:23pjstadighaha!
16:23hiredman:(
16:23pjstadiginformation at the speed of twitter!
16:23WizardofWestmarcoh my new clojure book beta? *goes*
16:24WizardofWestmarchm, looks like it isn't uploaded yet, as it hasn't switched to "regenerate pdf"
16:24hiredmanis it too much? should I unhook the tweets?
16:25WizardofWestmarchiredman: I'd say yes, anyone who cares can just rss the feed
16:25WizardofWestmarcthat's what I have set up anyway
16:27cemerickhiredman: you could hook -clojurebot up to its own twitter account that we could follow :-P
16:28hiredmanoh, hmmmm, for svn messages?
16:28WizardofWestmarcsvn messages I like, personally
16:28cemerickoh, that'd be handy too, but I meant for the twitter feed as well
16:28WizardofWestmarcthey don't tend to flood the room but are useful to see
16:29cemerickI need to figure out how to get all my rss feeds into something I can follow on twitter.
16:29WizardofWestmarchah
17:04brennancbrand new to clojure here. I'm going through the programming clojure book and am trying to figure out how the "examples" folder is included. I created my own folder and put a .clj file in there but I can't load it using "use". What do I need to do so I can use "use"
17:05Chouserbrennanc: the examples from the git project are loading, but not your own .clj files?
17:10lenst /quit
17:16WizardofWestmarcwonder how long it takes for a new book upload by the pragprog guys to hit the gerbils
17:19scottjAre contrib and slime up-to-date with the fully-lazy changes?
17:19scottjor clojure-swank rather
17:19digash`scottj: yes, i am using it.
17:25hiredmanwhat
17:25hiredmanI thought I disabled that
17:38danlarkinthe tweets will never die!
17:39hiredmansomeone should tell them that those stars mean a var that it is intended to be rebound
17:40Chouserhow ironic
18:04brennancChouser: I guess I don't really know how the include system works. How do I invoke Clojure and tell it where to look?
18:07Chouserbrennanc: the simplest way to load a single file is (load-file "foo.clj")
18:07Chouserthat'll load "foo.clj" from your current working directory
18:16brennancnot able to get that to work. doesn't seem to take a string
18:16brennancuser=> (load-file "my-test.clj")
18:16brennancjava.lang.RuntimeException: java.lang.RuntimeException: java.lang.IllegalArgumentException: Don't know how to create ISeq from: Symbol (my-test.clj:1)
18:20danlarkinbrennanc: that means my-test has an error
18:20danlarkinnot the call to load-file
18:21danlarkinyou probably have an error in your namespace definition, judging from the error
18:28hiredmandanlarkin: I kind of get the feeling he may not have a namespace declaration
18:29blbrownis pircbot still the standard irc bot or has something better come along
18:30hiredmanpircbot is nice and simple
18:45twopoint718I had a facepalm moment just now with using a quoted ns call when it shouldn't have been.
18:47twopoint718brennanc: check your ns or in-ns call, it could be the same thing.
19:16brennancok, thanks, guys. How do I add a directory of .clj files to the class path so I can use it with "use"?
19:19brennancdo I need to jar up the whole folder each time and put that jar in the class file or can I just have it look in a folder?
19:19Chouserno need to jar
19:20Chouserfor a namespace foo.bar.baz, put the code in a file src/foo/bar/baz.clj, and put src in your classpath
19:21Chouserthen you can say (use 'foor.bar.baz)
19:25brennancby put src in my classpath you mean like "export CLASSPATH=$CLASSPATH:/full-path-to/src"?
19:25Chouseryes
19:26Chousernote that -cp on the java command line will cause the CLASSPATH env var to be ignored
19:30brennancI modified the repl.sh to add the folder that has my .clj but it still is complaining that it can't find my file in the classpath
19:32brennancdo I need to add a ns at the beginning of my .clj file?
19:32Chouseryes
19:34Chouserif you're still having trouble, paste your classpath, .clj file, and the error you're getting
19:34Chouserlisppaste8: url
19:34lisppaste8To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste.
19:37brennancgot it. I had to add namespace like "folder.base-file-name". I was just doing "ns folder"
19:37brennancthe repl.sh includes the classpath with a simple "." for the CWD
19:42Chousergreat
19:47mrsolois there something in closure api so that (eq? 'a 'a) => true?
19:47Chouser,(= 'a 'a)
19:47clojurebottrue
19:48Chouseris that what you mean?
19:48mrsoloduh
19:48mrsoloi typed = wrong..nm
19:48mrsoloyep
19:48mrsolothanks :-)
19:48Chousernp
19:50slashus2,(contains? [1 2 3] 3)
19:50clojurebotfalse
19:51Chouser,(contains? '[a b c] 1)
19:51clojurebottrue
19:55slashus2I guess it doesn't work the same as (.contains [1 2 5] 5)
19:56slashus2Works on maps :-|
19:57Chouservectors map from index to value
19:58Chouser'contains?' tells you if the index exists
19:58slashus2I get that now.
19:58Chouserif you're doing membership checks, a set is faster and more convenient
19:58Chouser,('#{a b c} 'b)
19:58clojurebotb
19:58Chouser,('#{a b c} 'd)
19:58clojurebotnil
20:01slashus2Okay, neat.
20:02slashus2,(some #{20} [1 2 20])
20:02clojurebot20
20:02Chouserdid you read that somewhere?
20:03slashus2I was just playing around with some.
20:04slashus2Why?
23:16danlarkinso a var is like a thread-local variable, I want to update it with each call to a function
23:16danlarkinwith atoms I would use swap!
23:16danlarkinbut I don't want an atom, since that'll be cross-thread
23:17Chouserset!
23:18danlarkinit complained that it can't change/establish a root binding with set!
23:18danlarkinbut I have (def *blocks* {}), am I missing something?
23:26danlarkinChouser: ping
23:31cmvkki think you have to use binding first?
23:31danlarkinohh, you are probably right
23:31Chouseryep
23:38Chouserbinding pushes a thread-local context, and 'set!' can change that.
23:39Chouserto change the root, use alter-var-root, but of course that's shared among threads.
23:41danlarkinI will have to find the proper place to establish a binding