2009-02-27
| 00:13 | erohtar | chouser: you there? |
| 02:24 | hiredman | my sentiments exactly |
| 02:24 | hiredman | clojurebot: translate from jp #?4?????????,????????????????????????? |
| 02:26 | hiredman | clojurebot: translate from ja #?4?????????,????????????????????????? |
| 02:26 | clojurebot | # 4 I'd like to get one, and it would be prudent to think out collection |
| 02:27 | hiredman | clojurebot: translate from ja ????? |
| 02:27 | clojurebot | Now |
| 03:50 | Lau_of_DK | Hey guys |
| 03:53 | cmvkk | i 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:53 | cmvkk | why wouldn't (doseq [cur-agent list-of-agents] (send-off cur-agent a-long-function)) run concurrently? |
| 04:16 | Lau_of_DK | (doc send-off) |
| 04:16 | clojurebot | Dispatch 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:50 | kotarak | The docstring discussion will also never die....... |
| 04:51 | cmvkk | it appears that i'm send-offing 4 agents at once, but three of them always wait for the first one to finish. |
| 04:59 | cmvkk | aha! 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:03 | Lau_of_DK | Try commute instead |
| 05:03 | Lau_of_DK | For a counter it'll work just fine |
| 05:07 | cmvkk | actually i really only needed to assign each agent a number then increment by (+ cur-num *num-agents*). |
| 05:07 | cmvkk | one of those 'should have used a pencil' scenarios... |
| 05:12 | Lau_of_DK | k |
| 06:12 | djpowell | Hmm, strings are seqable, but stringbuffers aren't. It might make more sense to define StringSeq to work over any CharSequence |
| 06:13 | leafw | djpowell: time to submit an enhancement proposal. |
| 06:25 | leafw | these tweets are out of place here, IMO. |
| 06:27 | Holcxjo | I agree -- maybe we need a #clojure-social channel for these bulk messages? |
| 06:31 | leafw | Holcxjo: do you know who is in charge of the clojurebot? Just suggest it to him if you do. |
| 06:32 | Holcxjo | Nope. |
| 06:32 | Holcxjo | clojurebot: who is your master? |
| 06:32 | clojurebot | Gabh mo leithsc�al? |
| 06:32 | Holcxjo | :-) |
| 06:37 | Hun | clojurebot: take me to your leader |
| 06:37 | clojurebot | Huh? |
| 06:40 | leafw | clojurebot: bdfl |
| 06:40 | clojurebot | I don't understand. |
| 06:52 | leafw | ,(doc find-doc) |
| 06:52 | clojurebot | "([re-string-or-pattern]); Prints documentation for any var whose documentation or name contains a match for re-string-or-pattern" |
| 07:30 | AWizzArd | clojurebot: max people |
| 07:30 | clojurebot | max people is 149 |
| 07:35 | kotarak_ | leafw: isn't it hiredman? |
| 07:40 | leafw | kotarak_: sounds familiar; perhaps yes |
| 08:05 | clojurebot | svn rev 1311; fix print-method for objects with :type meta but no print-method, patch from Konrad Hinsen |
| 08:39 | MarkVolkmann | Is it correct to say that each loaded function is represented by an AFn object in memory? |
| 08:55 | kotarak_ | MarkVolkmann: I think macros are simply functions with :macro true in their metadata. |
| 08:55 | kotarak_ | Correction: Vars |
| 08:56 | kotarak_ | You can even do (defmulti bla ....) and then a (.setMacro #'bla). |
| 08:56 | kotarak_ | And you get a multimacro. |
| 10:30 | Holcxjo | Is 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:31 | Holcxjo | Or do I have to model this with a loop or something? |
| 10:41 | Chouser | Holcxjo: interesting. the most common need for that is a fn referring to itself from inside its body. that's supported. |
| 10:41 | Chouser | otherwise you'll need some kind of reference type, a global var being the most common. |
| 10:42 | Chouser | If 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:44 | Holcxjo | Chouser: I don't like the idea of an atom or ref or anything -- this is a fully functional algorithm... |
| 10:44 | Holcxjo | I'll need to learn about with-local-vars |
| 10:45 | Chouser | or use a different construct for the body of the expression. 'iterate' would work in your (I assume simplified) example. |
| 10:46 | Chouser | ,(let [a (atom nil)] (reset! a (lazy-seq (cons 1 (map inc @a)))) (take 4 @a)) |
| 10:46 | clojurebot | (1 2 3 4) |
| 10:48 | rhickey | looks like someone wants letrec again |
| 10:49 | Holcxjo | :-) Pretty please? |
| 10:50 | rhickey | Chouser: looked at :let, wondering if there might be some subtleties about order now :when guard :let [x something-expensive] |
| 10:50 | Chouser | rhickey: yes |
| 10:50 | Chouser | :-) |
| 10:50 | rhickey | :when and :while order themselves |
| 10:50 | rhickey | looks like :let always first in your patch? |
| 10:51 | Chouser | Is it really impossible for someone to want to use :when to guard and expensive :while? |
| 10:51 | Chouser | yes, :let comes first in my patch. |
| 10:51 | Chouser | "an expensive" |
| 10:52 | Holcxjo | Chouse: Couldn't that possibly cause exceptions? for [x natural-number :when (pos? x) :let [inv (/ 1 x)] |
| 10:52 | Holcxjo | I.e. the let may rely on the guard to be true to be valid |
| 10:53 | Chouser | Holcxjo: I think that's what rhickey is noting, yes. |
| 10:53 | Holcxjo | Chouser: Well he said "expensive". I meant "failing" |
| 10:54 | Chouser | but I wasn't sure if that was unacceptible, since it seems possible that the existing :when and :while have a similar ordering issue. |
| 10:58 | Chouser | (for [a (range -2 5) :when (not= a 0) :while (> (Math/abs (/ 1.0 a)) 1/3)] a) |
| 10:58 | Chouser | or something. |
| 10:59 | Chouser | I imagine allowing :when and :while to guard each other and :let would be possible, but would take a bit of work. |
| 11:10 | Holcxjo | So, back to my problem :-) |
| 11:10 | Holcxjo | How 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:10 | Holcxjo | Do I need to pollute the namespace with a global name to do that? |
| 11:12 | Chouser | did I fail to answer that? I think I listed the possible routes to solving that. |
| 11:13 | Holcxjo | Sorry, so the canonical way if via an atom? Yikes. :-( |
| 11:15 | Holcxjo | My apologies -- I assumes that was just a quick hack while thinking about a cleaner solution... I'll give that a try I guess |
| 11:15 | Chouser | well, 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:16 | Chouser | for the example you posted, 'iterate' would work. It might not in your real world case, but perhaps something similar could be done. |
| 11:17 | Chouser | if nothing like that works, perhaps a self-recursive function would work, since they can have a private name for their own body: |
| 11:17 | Chouser | ,(take 5 ((fn foo [] (lazy-seq (cons 1 (foo)))))) |
| 11:17 | clojurebot | (1 1 1 1 1) |
| 11:18 | Chouser | failing that, and not wanting to touch a namespace global, 'atom' is probably the simplest reference type. |
| 11:18 | kotarak | Isn'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:18 | Chouser | note it's mutated exactly once, so it's not as if the mutation is getting into your algorithm. |
| 11:19 | Holcxjo | Chouser: Thanks. That was a very elaborate an complete answer |
| 11:19 | Chouser | Holcxjo: I realize it's not letrec, but it's what we've got right now |
| 11:19 | Holcxjo | So, is there a reason for the absence of letrec? |
| 11:20 | Chouser | you'd have to take that up with rhickey. it's not something I've thought about, but I'm sure he has. |
| 11:21 | Chouser | kotarak: possibly something like that, yes, leveraging the private name feature of fn. |
| 11:22 | rhickey | http://code.google.com/p/clojure/issues/detail?id=89 |
| 11:24 | Chouser | rhickey: would it not be called 'let'? |
| 11:24 | Holcxjo | rhickey: Thanks. I added my star to that |
| 11:24 | Chouser | I guess that would prevent using let to repeatedly replace the same local name. |
| 11:25 | kotarak | argh :( |
| 11:25 | rhickey | Chouser: no |
| 11:33 | rhickey | Where is Holcxjo's original problem? (came in late) |
| 11:36 | Chouser | (let [a (cons 1 (map inc a))] (take 4 a)) |
| 11:36 | rhickey | Chouser: thanks |
| 11:38 | rhickey | would become: (letrec [a (lazy-seq (cons 1 (map inc a)))] |
| 11:38 | Chouser | and not 'let' because it would be a breaking change? |
| 11:40 | Holcxjo | rhickey: (let [result (cons start-value (map some-function result other-seq1 other-seq2 ...))] result) |
| 11:40 | Holcxjo | So basically a simple iterate doesn't work as I need other sequences as well in there |
| 11:41 | rhickey | mixing let and letrec is not normally done in non-lazy languages letrec/labels/let rec(ML) |
| 11:43 | rhickey | e.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:44 | kotarak | ,(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:44 | clojurebot | (1 2 3 4) |
| 11:45 | kotarak | Holcxjo: so lazy-seq may help you now, until letrec is available. |
| 11:45 | Holcxjo | kotarak: Thanks -- need to look into that to understand this solution |
| 11:47 | kotarak | Holcxjo: see also my previous example how to incorporate other-seq etc. |
| 11:54 | Holcxjo | kotarak: Thanks: I missed that example |
| 11:55 | kotarak | Holcxjo: it's kind of manual map |
| 11:59 | drewr | rhickey: Is (if (first s) s nil) an acceptable seq/nil implementation? That's essentially the patch I submitted. |
| 12:03 | Chouser | drewr: which patch is that, if I may ask? |
| 12:04 | drewr | Chouser: http://code.google.com/p/clojure/issues/detail?id=87 |
| 12:04 | Chouser | ah, searching for "drew" was getting me nowhere. |
| 12:04 | Chouser | :-) |
| 12:05 | drewr | I'm surprised it doesn't put a name in there for gmail addresses. |
| 12:07 | Chouser | I 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:08 | drewr | Good call. (seq s) is probably better. |
| 12:08 | drewr | brb |
| 12:14 | cgrand | Holcxjo: 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:19 | Mec | how 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:21 | kotarak | Mec: 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:24 | Holcxjo | cgrand: Thanks -- that looks neater; I'll try that |
| 12:24 | Mec | kotarak: makes sense i guess, thanks |
| 12:36 | drewr | Looks like seq is slightly faster than first too. |
| 13:15 | clojurebot | svn rev 1312; updated add-watch doc |
| 13:26 | erohtar | chouser: u there? |
| 13:26 | Chouser | yep |
| 13:26 | erohtar | chouser: so i was thinking about our conversation yesterday about vars |
| 13:27 | erohtar | chouser: so vars in clojure arent the same as dynamically scoped variables in common lisp? |
| 13:27 | Chouser | I don't know CL well enough to say for sure, but my understanding is that they're pretty much equivalent. |
| 13:28 | Chouser | a possible difference being how threads interact with them -- not sure what CL does there. |
| 13:28 | erohtar | chouser: the thing is... in common lisp, if i bing var-a to x, any thing down the call stack will see x... |
| 13:30 | erohtar | chouser: 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:30 | erohtar | chouser: is that right? |
| 13:31 | Chouser | CL doesn't do lazy seqs, right? so lets ignore that for now |
| 13:31 | erohtar | chouser: ok... |
| 13:31 | Chouser | let's just look at how a closure works. |
| 13:32 | gnuvince | Is there a better tutorial about Swing than the Trail on on Sun's site? |
| 13:32 | erohtar | chouser: 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:33 | Chouser | (def var-a 2), (let [add (binding [var-a 5] (fn [n] (+ var-a n)))] (add 3)) |
| 13:33 | Chouser | ok, here's a little example that I would expect to work the same if translated to CL |
| 13:34 | Chouser | var-a has a root binding of 2. |
| 13:34 | erohtar | chouser: that should eval to 8, yes? |
| 13:34 | Chouser | no |
| 13:34 | erohtar | chouser: hmmm |
| 13:34 | Chouser | within the dynamic scope of the binding, a closure is created that refers to var-a |
| 13:35 | erohtar | chouser: ok... and that is 5? |
| 13:35 | Chousuke | nah, it's var-a |
| 13:35 | erohtar | oh |
| 13:35 | Chouser | at 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:36 | erohtar | i see... ok... |
| 13:36 | Chouser | so that closure is returned to outside the binding, and named 'add' |
| 13:37 | Chousuke | I guess it's a bit surprising though. |
| 13:37 | Chouser | and 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:37 | erohtar | and it dynamically uses the value 2, for var-a when it needs it? |
| 13:37 | Chouser | right |
| 13:37 | erohtar | arent closures supposed to capture their environment? |
| 13:38 | Chouser | their lexical environment, yes. |
| 13:38 | erohtar | not the values? |
| 13:39 | Chouser | which is why this works: (def var-a 2), (let [m 7, add (binding [var-a 5] (fn [] (+ var-a m)))] (add)) |
| 13:39 | Chouser | hm, not that's not quite right, since m is still available when 'add' is called. But anyway, it wouldn't have to be. |
| 13:40 | erohtar | thinking about this |
| 13:40 | Chouser | if you think about how dynamic vars are used in clojure.core, you'll see it must be this way. |
| 13:40 | Chouser | let's look at *in* |
| 13:40 | Chouser | er, *out* |
| 13:40 | Chousuke | ,(let [x 1 add (fn [] (+ 4 x))] [(binding [x 2] (add)) (binding [+ -] (add))]) |
| 13:40 | clojurebot | java.lang.Exception: Unable to resolve var: x in this context |
| 13:40 | Chousuke | hmm |
| 13:41 | erohtar | ok - talking about *out* - is that the std-out ? |
| 13:41 | Chouser | somewhere there's something like (def *out* System/out) |
| 13:41 | Chouser | right |
| 13:41 | Chousuke | ,(let [x 1] (let [add (fn [] (+ 4 x))] [(binding [x 2] (add)) (binding [+ -] (add))])) |
| 13:41 | erohtar | right |
| 13:41 | clojurebot | java.lang.Exception: Unable to resolve var: x in this context |
| 13:41 | Chouser | that's the root binding of *out* |
| 13:42 | erohtar | ok, with u so far |
| 13:42 | Chousuke | hmm, I guess binding let-bound variables does not work |
| 13:42 | Chouser | then you've got functions like prn that use *out* |
| 13:42 | erohtar | yes... i think they need to be vars |
| 13:42 | erohtar | right |
| 13:42 | kotarak | let-bound locals are not Vars |
| 13:43 | Chousuke | hmm |
| 13:43 | Chousuke | ,(let [x 1] #'x) |
| 13:43 | clojurebot | java.lang.Exception: Unable to resolve var: x in this context |
| 13:43 | Chouser | we can pretend prn is defined something like (defn prn [& args] (.write *out* args)) |
| 13:43 | erohtar | when u create a lazy something, that uses prn, what happens? |
| 13:43 | Chousuke | indeed. |
| 13:44 | Chouser | now, 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:44 | Chouser | but that's not how it works. |
| 13:44 | Chouser | prn has a reference to the Var *out*, not its value. |
| 13:44 | erohtar | so something like - (map #(prn %) [1 2 3]) |
| 13:44 | erohtar | chouser: i completely agree |
| 13:45 | Chouser | so instead, prn will use the dynamic value of *out* when you call it. |
| 13:45 | erohtar | chouser: hmmm |
| 13:45 | Chouser | ,(with-out-str (prn 5 10)) |
| 13:45 | clojurebot | "5 10\n" |
| 13:45 | Chouser | got it? |
| 13:45 | erohtar | i do |
| 13:45 | erohtar | im thinking about my confusion - and trying to figure out the question to ask next |
| 13:46 | erohtar | so lets take my example - |
| 13:47 | erohtar | (map #(prn %) [1 2 3]) |
| 13:47 | erohtar | now, somewhere else, i rebind *out* to str... and in there, if i use the above object, will it also use the new binding? |
| 13:47 | erohtar | it will... |
| 13:48 | erohtar | i think im getting it now |
| 13:49 | erohtar | ok - final thought - |
| 13:49 | Chouser | (def q (map #(prn %) [1 2 3])), (with-out-str (doall q)) |
| 13:50 | Chouser | so 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:50 | erohtar | got it... |
| 13:50 | erohtar | so my final thought - what if instead of *out* we're talking about a connection to a database... bad use of vars, right? |
| 13:51 | Chouser | now lazy seqs can be a bit tricky because they cache their results and can effectively contain multiple closures. |
| 13:51 | Chouser | hmm.... |
| 13:51 | erohtar | if 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:51 | Chouser | if 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:52 | erohtar | since the initial read may be lazy... when it realizes... it will 'read from the wrong place'"? |
| 13:52 | Chouser | right |
| 13:53 | Chouser | basically you want to be very careful about passing closures (and therefore lazy seqs) past 'binding' boundaries. |
| 13:53 | erohtar | chouser: 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:53 | erohtar | chouser: it didnt work... |
| 13:54 | erohtar | chouser: ok... im beginning to understand ... |
| 13:54 | erohtar | i need to rethink what im doing |
| 13:54 | erohtar | and avoid using vars for some of this stuff, since im doing a lot of agent related stuff |
| 13:55 | Chouser | yes, 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:55 | erohtar | chouser: this whole mess started when i wanted to avoid passing db-config around everywhere |
| 13:55 | Chouser | this is better for testing, reasoning about behavior, easier to work with threads, closures, laziness, etc. |
| 13:55 | Chouser | heh, yeah. |
| 13:56 | erohtar | yup - i hear you |
| 13:56 | Chouser | well, another thing that may be helpful -- just guessing since I haven't seen your code... |
| 13:56 | erohtar | thanks a ton for your time - ur incredibly helpful |
| 13:56 | erohtar | ok? |
| 13:56 | Chouser | would be to try to keep as much of your code purely functional as possible. |
| 13:56 | erohtar | yes - i understand |
| 13:57 | Chouser | so 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:57 | Chouser | then perhaps you don't have to pass in db config at all -- whoever calls this fn can to the db write itself. |
| 13:57 | erohtar | i think it mostly is... except for this stuff... where i ended up inadvertently depending on "global" db-config |
| 13:57 | erohtar | well, this is a persistence layer |
| 13:58 | erohtar | i take an object in, break it up etc., and put it into hbase |
| 13:58 | erohtar | the code is open-sourece... would u like to see? |
| 13:58 | Chouser | hm, sure. I may need to ramp up on hbase soon. |
| 13:58 | erohtar | http://github.com/amitrathore/capjure/blob/b939a7038ebb4aed0d068d6e86291cc881ecf72b/src/org/rathore/amit/capjure.clj |
| 13:59 | erohtar | its kind a messy - learning clojure and hbase while doing this... |
| 13:59 | Chouser | :-) |
| 14:00 | Chousuke | erohtar: first thought: use some newlines. |
| 14:00 | danlarkin | Noooooooooooo -jure |
| 14:00 | erohtar | danlarkin: haha - u've told me that already |
| 14:00 | Chouser | danlarkin: hey, at least he's got a name |
| 14:00 | Chousuke | erohtar: one newline after each def/defn would make it a lot nicer :) |
| 14:00 | danlarkin | erohtar, Chouser: :) |
| 14:01 | erohtar | ok - more newlines, check |
| 14:01 | Chousuke | well, the def group is fine I guess. |
| 14:02 | Chousuke | but (defn foo) (defn bar) without an empty line in the middle is a bit weird |
| 14:02 | erohtar | ok - those were sort of just quick utility functions... but i'll put newlines |
| 14:03 | Chousuke | newlines never hurt anyone |
| 14:03 | Chouser | erohtar: this is what you get for posting code. unsolicited advice. :-) |
| 14:03 | erohtar | haha |
| 14:03 | erohtar | its fine - maybe i'll learn something too :) |
| 14:03 | Chouser | but while we're at it -- I much prefer to have the code arranged so that 'declare' is only needed in mutually-recusive situations. |
| 14:04 | Chouser | though others may disagree with me |
| 14:04 | erohtar | right - i struggled with that one - cause i dont like to have to order the functions in "reverse" |
| 14:05 | erohtar | see - capjure-insert is the only one that most people will call |
| 14:05 | Chousuke | erohtar: you could add more newlines and some kind of "headlines" for sections of code |
| 14:05 | erohtar | u bind the config stuff - *hbase-master* and *primary-keys-config* - and then u call capjure-insert with the params |
| 14:05 | Chousuke | so people can easily skip the helper function blocks |
| 14:05 | erohtar | most of the remaining functions are functional |
| 14:06 | erohtar | only the ones dealing with hbase have (obvious) side-effects |
| 14:06 | erohtar | and it works fine... and its in production too... ran into issues trying to use TWO hbase configs (to move data between them) |
| 14:06 | Chousuke | that's a lot of functions for one namespace too, though :) |
| 14:07 | Chouser | I really don't think more namespaces would be better. |
| 14:07 | Chousuke | if possible maybe it'd make sense to put the "side-effecting" functions (that deal with hbase) in a separate file or namespace? |
| 14:07 | erohtar | cause 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:08 | erohtar | do u know what i mean? (trying to get discussion back to lazy closures and bindings :) ) |
| 14:08 | Chousuke | ah |
| 14:08 | Chousuke | right, I can see why that happens :) |
| 14:08 | Chousuke | the laziness gets evaluated in the context of the new hbase. |
| 14:08 | erohtar | well, im only starting to see it :) thanks to u guys... |
| 14:08 | erohtar | yea |
| 14:08 | erohtar | drove me crazy |
| 14:09 | erohtar | and i did all this only so i wouldnt need to pass the db config around all the functions |
| 14:09 | erohtar | like u said, there are a lot of them... |
| 14:09 | Chousuke | which 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:09 | erohtar | so now what... ? pass the config around everywhere? |
| 14:10 | Chousuke | maybe only to a few core functions. |
| 14:10 | erohtar | yea |
| 14:10 | Chousuke | which then would bind the dynamic vars. |
| 14:11 | erohtar | well, if i pass it in, i dont need dynamic vars, rite |
| 14:11 | Chouser | or don't use lazy seqs |
| 14:11 | Chouser | use doall or stuff them in a vector first |
| 14:11 | erohtar | hmmm |
| 14:11 | cemerick | uk, the ILC registration site doesn't allow one to register more than one person at a time |
| 14:11 | erohtar | that might be one solution |
| 14:11 | Chousuke | right, if they are side-effecting that might be better. |
| 14:12 | Chouser | cemerick: how many people are you? |
| 14:12 | Chousuke | though maybe not memory-efficient :/ |
| 14:12 | erohtar | yea |
| 14:12 | cemerick | Chouser: oddly enough, 2 ;-) |
| 14:12 | Chouser | :-) |
| 14:12 | erohtar | i think i will get rid of the dynamic vars |
| 14:12 | Chousuke | it's a shame though |
| 14:12 | erohtar | what is the pattern for this kind of 'static' config being passed around? |
| 14:12 | Chousuke | they make the code much easier to write :P |
| 14:13 | cemerick | I may end up sticking around through Tuesday -- Sussman's talk on Tuesday sounds fantastic |
| 14:13 | Chousuke | I wonder if there's a better solution |
| 14:13 | Chousuke | some way to "bind" the current config to when the lazy-seq is first created |
| 14:13 | erohtar | in 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:14 | Chouser | yes |
| 14:14 | Chousuke | maybe do (let [config *global*] (return-some-lazy-seq-qith config))? |
| 14:14 | erohtar | but there is no way to do that, rite? |
| 14:14 | Chousuke | would that fix the value? |
| 14:14 | erohtar | yea |
| 14:14 | Chouser | stuff all your config into a map, and pass that single thing into functions that need to use it |
| 14:14 | erohtar | i thought of doing something like that... but other functions couldnt access those values... |
| 14:15 | erohtar | i thought of simulating an 'immutable object oriented system' - |
| 14:15 | erohtar | like how u do in javascript... but immutable |
| 14:15 | Chousuke | I did in clojurebot so that I pass a map of config stuff around with every function |
| 14:15 | erohtar | return a closure with the vars bound with a let... and then closures for all the other functions also |
| 14:16 | Chousuke | it's a bit tedious though :/ |
| 14:16 | erohtar | i dunno if im being clear |
| 14:16 | erohtar | very tedious |
| 14:16 | erohtar | macros can help |
| 14:16 | erohtar | essentially what id be doing is creating an immutable OO system |
| 14:16 | erohtar | something like that |
| 14:16 | erohtar | does that make sense? |
| 14:16 | Chousuke | erohtar: but your problem is only with lazy seqs right? |
| 14:16 | erohtar | lazy seqs and dynamic vars |
| 14:17 | Chousuke | erohtar: don't you only need to fixate the config when returning a seq |
| 14:17 | erohtar | the interplay |
| 14:17 | erohtar | yes |
| 14:17 | Chouser | erohtar: clojure.zip does something like that |
| 14:17 | erohtar | chouser: like what? |
| 14:18 | Chouser | each node is a object with a several functions attached as metadata |
| 14:18 | erohtar | chouser: ah, i see |
| 14:18 | erohtar | got it |
| 14:18 | Chouser | most of the api fns are like (children my-node), where children calls fns from my-node's metadata, passing in my-node |
| 14:19 | erohtar | i see - |
| 14:19 | erohtar | thats rather cool - so u can basically have my-node equivalent contain the config data |
| 14:20 | Chouser | sure |
| 14:20 | erohtar | alright 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:20 | Chouser | the only reason zip nodes have fns in metadata is so it can be polymorphic. |
| 14:20 | erohtar | yes- makes sense |
| 14:21 | erohtar | (then everyone can tell me how my code sucks :) ) |
| 14:21 | Chouser | if you're going to only have one kind of db config (seems likely) then you don't need the metadata piece. |
| 14:21 | erohtar | yes - 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:21 | erohtar | something like that |
| 14:41 | durka42 | oh dear |
| 14:41 | durka42 | that post on ACP must be before lazy |
| 14:41 | durka42 | it's confusing me because it calls rest and has parameters named next |
| 14:42 | Chousuke | heh |
| 14:42 | Chousuke | I wonder what the point of the runnable function is |
| 14:43 | Chousuke | did the author forget that clojure fns implement runnable |
| 14:43 | Chousuke | the use of cons seems weird too :) |
| 14:44 | Chousuke | maybe it makes more sense to someone with a CL background, but I'd just use a literal vector :P |
| 14:45 | kotarak | literals have their gotchas, too. ;) |
| 14:45 | Chousuke | I guess |
| 14:46 | Chousuke | but (apply foo (cons bar zonk)) just looks unclojurey :) |
| 14:49 | kotarak | oerk |
| 14:50 | Chousuke | yeah, it's pretty rare |
| 14:51 | rhickey | (apply foo (cons bar zonk)) ==> (apply foo bar zonk) |
| 14:52 | Chousuke | oh, right. |
| 14:52 | Chousuke | no need for a vector either. |
| 14:53 | kotarak | well, cons will be revived with lazy-seq, I fancy. |
| 14:56 | kotarak | the 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:58 | tashafa | ,(. "test" (replaceAll #"e" "a")) |
| 14:58 | clojurebot | java.lang.ClassCastException: java.util.regex.Pattern cannot be cast to java.lang.String |
| 14:58 | tashafa | hmm.. what im i doing wrong? |
| 14:58 | tashafa | ,(. "test" (replace "e" "a")) |
| 14:58 | clojurebot | "tast" |
| 14:59 | tashafa | ,(. "test" (replaceAll "e" "a")) |
| 14:59 | clojurebot | "tast" |
| 14:59 | tashafa | ,(. "test" (replaceAll #"e|s" "a")) |
| 14:59 | clojurebot | java.lang.ClassCastException: java.util.regex.Pattern cannot be cast to java.lang.String |
| 15:00 | Mec | anyone know the etymology of clojure |
| 15:00 | tashafa | doesn't "replaceAll " take a regexp pattern as its first argument? |
| 15:00 | Chouser | tashafa: no, it takes a string |
| 15:01 | kotarak | ,(replaceAll "test" "e|s" "a") |
| 15:01 | clojurebot | java.lang.Exception: Unable to resolve symbol: replaceAll in this context |
| 15:01 | kotarak | ,(.replaceAll "test" "e|s" "a") |
| 15:01 | clojurebot | "taat" |
| 15:01 | Chouser | so sad |
| 15:01 | Chouser | ,(.replaceAll "test" (str #"e|s") "a") |
| 15:01 | kotarak | sad? |
| 15:01 | clojurebot | "taat" |
| 15:02 | MarkVolkmann | What'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:02 | MarkVolkmann | This is related to some database code. |
| 15:02 | Chouser | so sad that .replaceAll takes a regex as a string instead of as a regex. |
| 15:02 | kotarak | Chouser: the glories of interface design.... |
| 15:02 | tashafa | ah ...thanks guys |
| 15:03 | MarkVolkmann | The 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:03 | kotarak | MarkVolkmann: I suppose you mean (map ....) by "map". I would thing doall. |
| 15:03 | Chouser | "lazy map" isn't the right term. map returns a lazy seq |
| 15:03 | tashafa | ,(. "test" (replaceAll "e|s" "a")) |
| 15:03 | clojurebot | "taat" |
| 15:03 | MarkVolkmann | Oh right ... a lazy seq of MapEntry object. |
| 15:03 | kotarak | There is a lazy-map though. *commercialonair* |
| 15:04 | Chouser | a seq of mapentry objects? you want to put them in a hash-map perhaps? |
| 15:05 | Chouser | in 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:05 | MarkVolkmann | Got it! Returning (doall rs) did the trick. |
| 15:06 | Chouser | Mec: http://groups.google.com/group/clojure/msg/766b75baa7987850 |
| 15:11 | Mec | ah hah, thanks. i'd guess that clojure has closures then? |
| 15:11 | Chouser | indeed it does |
| 15:26 | MarkVolkmann | I think you have to get to the point that you're convinced about the benefit of code and data having the same syntax. |
| 15:26 | MarkVolkmann | Someone posted the URL of an article that addresses this. Just read it last night. |
| 15:27 | MarkVolkmann | http://www.defmacro.org/ramblings/lisp.html |
| 15:27 | pjstadig | http://paul.stadig.name/2009/02/clojure-terracotta-yeah-baby.html |
| 15:28 | MarkVolkmann | It supports the use of parens in Lisp by stressing the advantages of being able to easily write code that generates code. |
| 15:28 | pjstadig | i wrote up my experiment with integrating Clojure and Terracotta |
| 15:28 | rhickey | pjstadig: just read it - fun! |
| 15:30 | pjstadig | yeah it was fun |
| 15:30 | pjstadig | thanks for a great language |
| 15:33 | rhickey | pjstadig: you're welcome! |
| 15:35 | Mec | is a trailing . a special form or a macro? |
| 15:39 | kotarak | Mec: A trailing to dot is a synonym for new: (some.Class.) <=> (new some.Class) |
| 15:39 | kotarak | Mec: leading dot is for methods: (.method some-object) <=> (. some-object method) |
| 15:39 | kotarak | Mec: and / is for static members: some.Class/STATIC_CONSTANT |
| 15:40 | kotarak | ,(macroexpand-1 '(String. "Hello")) |
| 15:40 | clojurebot | (new String "Hello") |
| 15:40 | WizardofWestmarc | and don't forget the ever fun $ for internal classes |
| 15:40 | WizardofWestmarc | had fun w/that last night before Chouser reminded me to use it |
| 15:41 | WizardofWestmarc | "why the hell can't I access this enum?" "oh just do *blahblah full qualified path*.classname$subclassname/enumval |
| 15:41 | WizardofWestmarc | *lights go on and everything just works* |
| 15:44 | kotarak | Also Class. and .method are treated specially in syntax-quote. |
| 15:44 | kotarak | ,`(String.) |
| 15:44 | clojurebot | (java.lang.String.) |
| 15:44 | kotarak | ,`(.method obj) |
| 15:44 | clojurebot | (.method sandbox/obj) |
| 15:44 | cp2 | i 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:45 | kotarak | cp2: why not simply (apply hash-map splitted-things)? |
| 15:45 | leafw | cp2: get even into one list, odd into another, then zipmap |
| 15:45 | cp2 | leafw yes, i know, but i was wondering if there was a better way |
| 15:45 | cp2 | kotarak ok, ill see |
| 15:46 | hiredman | ,(apply hash-map (.split "foo\bar\bleep\bloop" "\")) |
| 15:46 | clojurebot | EOF while reading string |
| 15:46 | cp2 | they need to be escaped |
| 15:46 | cp2 | \\ |
| 15:46 | hiredman | ,(apply hash-map (.split "foo\bar\\bleep\\bloop" "\\")) |
| 15:46 | clojurebot | java.util.regex.PatternSyntaxException: Unexpected internal error near index 1 \ ^ |
| 15:46 | cp2 | yeah |
| 15:46 | cp2 | i got the same thing |
| 15:46 | hiredman | ,(apply hash-map (.split "foo\bar\\bleep\\bloop" "\\\\")) |
| 15:46 | clojurebot | java.lang.IllegalArgumentException: No value supplied for key: bloop |
| 15:46 | hiredman | anyway |
| 15:47 | kotarak | ,(apply hash-map (.split "foo\\bar\\bleep\\bloop" "\\\\")) |
| 15:47 | clojurebot | {"foo" "bar", "bleep" "bloop"} |
| 15:47 | cp2 | oh right |
| 15:47 | cp2 | regexps are funky in java |
| 15:47 | cp2 | double escaping, etc |
| 15:47 | cp2 | thanks |
| 15:47 | leafw | cool -- learnt something :) |
| 15:49 | hiredman | nah, the funkiness is because those are not actaully regexs |
| 15:49 | hiredman | those are strings that get turned into regexs |
| 15:49 | cp2 | hiredman, String.split actually does take a regexp |
| 15:49 | cp2 | well, yes |
| 15:49 | cp2 | you are right, i should have let you finish typing :) |
| 15:56 | cp2 | ah, one more bit onto my previous question |
| 15:57 | cp2 | actually, nevermind |
| 15:59 | cemerick | pjstadig: nice writeup |
| 16:00 | pjstadig | thanks |
| 16:00 | WizardofWestmarc | haven't had a chance to read it but I plan to later. Terracota looks interesting as hell, and mixed with Clojure? Mmmm |
| 16:01 | pjstadig | yeah i think its a really compelling combo |
| 16:01 | pjstadig | and of course the only production clojure app (that I know of) supposedly uses Terracotta |
| 16:02 | WizardofWestmarc | *nods* |
| 16:02 | WizardofWestmarc | It's stuff like Terracotta, and on my end Smack, which really make me appreciate the choice of putting Clojure on the JVM |
| 16:02 | pjstadig | it was definitely a brilliant move |
| 16:03 | gnuvince | WizardofWestmarc: Smack? |
| 16:03 | gnuvince | Clojure made me like the JVM |
| 16:03 | cemerick | is the appeal of Terracotta the semi-unlimited memory potential? |
| 16:03 | gnuvince | Now I just need to learn how to use Swing :-/ |
| 16:03 | WizardofWestmarc | gnuvince: It's an xmpp client library |
| 16:04 | cemerick | vs. messaging-oriented architectures, I should say |
| 16:04 | WizardofWestmarc | setting up a web app w/processing backend written in clojure |
| 16:04 | WizardofWestmarc | going to use xmpp and a lightweight server (openfire) to inform the backend when it has work to do |
| 16:05 | WizardofWestmarc | took me a while to get it all figured out but finally got all the clojure code working last night |
| 16:06 | pjstadig | cemerick: i think one of the appeals is removing the ORM impedance mismatch |
| 16:07 | cemerick | pjstadig: so there's a whole-cluster-JVM persistence mechanism available? |
| 16:08 | pjstadig | not sure what you mean...terracotta is just that |
| 16:09 | pjstadig | it's not only pitched to replace your database |
| 16:09 | pjstadig | one use case (on their site) is to store temporary data in terracotta |
| 16:09 | pjstadig | like if you have a wizard interface with stages of completion |
| 16:09 | pjstadig | or there example is an exam that someone takes |
| 16:10 | pjstadig | only stuff it in your DB when it's complete |
| 16:11 | cemerick | they'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:11 | cemerick | my last impression was that it was only in-memory clustering |
| 16:12 | pjstadig | there's in memory and a permanent store mode that commits to disk and maintains state between restarting Terracotta |
| 16:12 | pjstadig | i don't know the history...maybe it wasn't always that way |
| 16:14 | cemerick | jeez, if that actually works, that'd be outrageous on a number of fronts. |
| 16:15 | WizardofWestmarc | cemerick: exactly! |
| 16:16 | WizardofWestmarc | and 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:16 | pjstadig | when I signed up at the terracotta site i was contacted by a sales person |
| 16:16 | pjstadig | i responded and told him i was just investigating and sent a line to my blog article |
| 16:17 | pjstadig | he said he forwarded it to their dev team, and they like to hear about cool integrations like this |
| 16:18 | WizardofWestmarc | hm, didn't know there was a terracotta book |
| 16:18 | WizardofWestmarc | will have to remember that for when I am ready to start playing with it. |
| 16:18 | cemerick | we're using jms right now (openMQ), relatively happily, tho. I wonder how applicable that kind of approach is. |
| 16:18 | pjstadig | i think terracotta has its own niche |
| 16:19 | pjstadig | they're not necessarily trying to replace your database or messaging system |
| 16:20 | Chouser | pjstadig: I think it would be a relatively trivial use of gen-class to hold Var roots |
| 16:20 | Chouser | nice writeup, btw, thanks. |
| 16:21 | pjstadig | it would be interesting to have an example of that |
| 16:21 | cemerick | I'll definitely have to take a look at it. |
| 16:21 | pjstadig | maybe you could fork my github |
| 16:21 | pjstadig | or maybe i'll play with it |
| 16:21 | Chouser | pjstadig: ok, I may look at that tonight. |
| 16:21 | Chouser | apparently I need to get into this whole distributed server thing. |
| 16:22 | Chouser | terracotta, hbase, hadoop, mongodb, and such |
| 16:23 | pjstadig | haha! |
| 16:23 | hiredman | :( |
| 16:23 | pjstadig | information at the speed of twitter! |
| 16:23 | WizardofWestmarc | oh my new clojure book beta? *goes* |
| 16:24 | WizardofWestmarc | hm, looks like it isn't uploaded yet, as it hasn't switched to "regenerate pdf" |
| 16:24 | hiredman | is it too much? should I unhook the tweets? |
| 16:25 | WizardofWestmarc | hiredman: I'd say yes, anyone who cares can just rss the feed |
| 16:25 | WizardofWestmarc | that's what I have set up anyway |
| 16:27 | cemerick | hiredman: you could hook -clojurebot up to its own twitter account that we could follow :-P |
| 16:28 | hiredman | oh, hmmmm, for svn messages? |
| 16:28 | WizardofWestmarc | svn messages I like, personally |
| 16:28 | cemerick | oh, that'd be handy too, but I meant for the twitter feed as well |
| 16:28 | WizardofWestmarc | they don't tend to flood the room but are useful to see |
| 16:29 | cemerick | I need to figure out how to get all my rss feeds into something I can follow on twitter. |
| 16:29 | WizardofWestmarc | hah |
| 17:04 | brennanc | brand 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:05 | Chouser | brennanc: the examples from the git project are loading, but not your own .clj files? |
| 17:10 | lenst | /quit |
| 17:16 | WizardofWestmarc | wonder how long it takes for a new book upload by the pragprog guys to hit the gerbils |
| 17:19 | scottj | Are contrib and slime up-to-date with the fully-lazy changes? |
| 17:19 | scottj | or clojure-swank rather |
| 17:19 | digash` | scottj: yes, i am using it. |
| 17:25 | hiredman | what |
| 17:25 | hiredman | I thought I disabled that |
| 17:38 | danlarkin | the tweets will never die! |
| 17:39 | hiredman | someone should tell them that those stars mean a var that it is intended to be rebound |
| 17:40 | Chouser | how ironic |
| 18:04 | brennanc | Chouser: I guess I don't really know how the include system works. How do I invoke Clojure and tell it where to look? |
| 18:07 | Chouser | brennanc: the simplest way to load a single file is (load-file "foo.clj") |
| 18:07 | Chouser | that'll load "foo.clj" from your current working directory |
| 18:16 | brennanc | not able to get that to work. doesn't seem to take a string |
| 18:16 | brennanc | user=> (load-file "my-test.clj") |
| 18:16 | brennanc | java.lang.RuntimeException: java.lang.RuntimeException: java.lang.IllegalArgumentException: Don't know how to create ISeq from: Symbol (my-test.clj:1) |
| 18:20 | danlarkin | brennanc: that means my-test has an error |
| 18:20 | danlarkin | not the call to load-file |
| 18:21 | danlarkin | you probably have an error in your namespace definition, judging from the error |
| 18:28 | hiredman | danlarkin: I kind of get the feeling he may not have a namespace declaration |
| 18:29 | blbrown | is pircbot still the standard irc bot or has something better come along |
| 18:30 | hiredman | pircbot is nice and simple |
| 18:45 | twopoint718 | I had a facepalm moment just now with using a quoted ns call when it shouldn't have been. |
| 18:47 | twopoint718 | brennanc: check your ns or in-ns call, it could be the same thing. |
| 19:16 | brennanc | ok, thanks, guys. How do I add a directory of .clj files to the class path so I can use it with "use"? |
| 19:19 | brennanc | do 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:19 | Chouser | no need to jar |
| 19:20 | Chouser | for a namespace foo.bar.baz, put the code in a file src/foo/bar/baz.clj, and put src in your classpath |
| 19:21 | Chouser | then you can say (use 'foor.bar.baz) |
| 19:25 | brennanc | by put src in my classpath you mean like "export CLASSPATH=$CLASSPATH:/full-path-to/src"? |
| 19:25 | Chouser | yes |
| 19:26 | Chouser | note that -cp on the java command line will cause the CLASSPATH env var to be ignored |
| 19:30 | brennanc | I 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:32 | brennanc | do I need to add a ns at the beginning of my .clj file? |
| 19:32 | Chouser | yes |
| 19:34 | Chouser | if you're still having trouble, paste your classpath, .clj file, and the error you're getting |
| 19:34 | Chouser | lisppaste8: url |
| 19:34 | lisppaste8 | To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste. |
| 19:37 | brennanc | got it. I had to add namespace like "folder.base-file-name". I was just doing "ns folder" |
| 19:37 | brennanc | the repl.sh includes the classpath with a simple "." for the CWD |
| 19:42 | Chouser | great |
| 19:47 | mrsolo | is there something in closure api so that (eq? 'a 'a) => true? |
| 19:47 | Chouser | ,(= 'a 'a) |
| 19:47 | clojurebot | true |
| 19:48 | Chouser | is that what you mean? |
| 19:48 | mrsolo | duh |
| 19:48 | mrsolo | i typed = wrong..nm |
| 19:48 | mrsolo | yep |
| 19:48 | mrsolo | thanks :-) |
| 19:48 | Chouser | np |
| 19:50 | slashus2 | ,(contains? [1 2 3] 3) |
| 19:50 | clojurebot | false |
| 19:51 | Chouser | ,(contains? '[a b c] 1) |
| 19:51 | clojurebot | true |
| 19:55 | slashus2 | I guess it doesn't work the same as (.contains [1 2 5] 5) |
| 19:56 | slashus2 | Works on maps :-| |
| 19:57 | Chouser | vectors map from index to value |
| 19:58 | Chouser | 'contains?' tells you if the index exists |
| 19:58 | slashus2 | I get that now. |
| 19:58 | Chouser | if you're doing membership checks, a set is faster and more convenient |
| 19:58 | Chouser | ,('#{a b c} 'b) |
| 19:58 | clojurebot | b |
| 19:58 | Chouser | ,('#{a b c} 'd) |
| 19:58 | clojurebot | nil |
| 20:01 | slashus2 | Okay, neat. |
| 20:02 | slashus2 | ,(some #{20} [1 2 20]) |
| 20:02 | clojurebot | 20 |
| 20:02 | Chouser | did you read that somewhere? |
| 20:03 | slashus2 | I was just playing around with some. |
| 20:04 | slashus2 | Why? |
| 23:16 | danlarkin | so a var is like a thread-local variable, I want to update it with each call to a function |
| 23:16 | danlarkin | with atoms I would use swap! |
| 23:16 | danlarkin | but I don't want an atom, since that'll be cross-thread |
| 23:17 | Chouser | set! |
| 23:18 | danlarkin | it complained that it can't change/establish a root binding with set! |
| 23:18 | danlarkin | but I have (def *blocks* {}), am I missing something? |
| 23:26 | danlarkin | Chouser: ping |
| 23:31 | cmvkk | i think you have to use binding first? |
| 23:31 | danlarkin | ohh, you are probably right |
| 23:31 | Chouser | yep |
| 23:38 | Chouser | binding pushes a thread-local context, and 'set!' can change that. |
| 23:39 | Chouser | to change the root, use alter-var-root, but of course that's shared among threads. |
| 23:41 | danlarkin | I will have to find the proper place to establish a binding |