#clojure logs

2008-07-15

06:41meredyddHmm...so, what happens when you invoke a (ref)?
08:14mac__meredydd: I guess the value of the ref gets treated as a function? So if you have something else than a function in it (like an integer) it will throw an exception. Not sure I understod the question
08:14mac__((ref 1)) -> error
08:14mac__((ref (fn [] "Hello World"))) -> works
08:15rhickeymac__: what question?
08:16mac__meredydd: Hmm...so, what happens when you invoke a (ref)?
08:17mac__asked almost 2 hours ago though, might not be here anymore?
08:17rhickeyah, I see it now at http://clojure-log.n01se.net/date/2008-07-15.html
08:18rhickeyThat behavior of refs is undocumented and subject to change
08:18mac__k
08:18mac__I just replied with what I observed :) good to know it could change
08:19mac__By the way, I'm a newbie lisp and functional programmer and I have a question of my own. I have a nasty loop from a java example I want to convert to clojure and I can't get my head around it...
08:19rhickeythere was a time (prior to release) when vars and refs were the same thing, i.e. vars were transactional and you could dynamically rebind refs, but I found it to be too confusing
08:20rhickeymac__: shoot
08:20rhickeyor maybe paste
08:20mac__ok, let me just paste the java code somewhere it
08:20mac__it's a nested loop
08:22lisppaste8mac__ pasted "nested loop" at http://paste.lisp.org/display/63725
08:24mac__tell me if you need more info there is some surrounding code too but that's the loop I'm having trouble with
08:25mac__util.join returns a java array with 1 or 2 shapes depending on if they could be joined or not
08:25rhickeymac__: nested fors map readily to Clojure's for...
08:25mac__sorry util.union I mean
08:25rhickeysetting aside the fact that the body does its work by side effect...
08:26rhickey(for [i (range (.size shapes)) j (range 1 (.size shapes))] ...)
08:28rhickeyone of the basic problems with imperative loops like that is that the logic is all gnarled up, difficult to read and understand...
08:28rhickeyso splitting it up into steps is important...
08:28rhickeyfirst step is making a list of items to keep/drop...
08:29mac__yeah tell me about it.. I spent a long time just looking at that before getting it. I've tried a few things but that innermost return haunts me
08:29rhickeythen build a result set, which in Clojure you would do functionally, maybe with reduce, rather than mutating a collection in place
08:30rhickeyor you could just reduce from the start...
08:31mac__yeah I've been trying some variants with reduce but never got it right, I just couldnt come up with something that combines every item with every other item in turn
08:31mac__I might just need more coffee :) right now I'm stuck
08:32rhickeythe outer structure would look like:
08:32rhickey(reduce (fn [ret [i j]] ...) [] (map vector (range (.size shapes)) (range 1 (.size shapes))))
08:34rhickeyoops, no, I see you need every combination, so for is better
08:35mac__ok, I've never used for, taking baby steps here :)
08:36rhickeytry this to get a feel for it:
08:36rhickey(for [i (range 5) j (range 1 5)] [i j])
08:40mac__yeah that's nice, just the nested loop effect I need, but I'm a bit hung up on the return in the innermost loop still, how do I stop it if I find a shape union?
08:41rhickeyif you do it in steps, you'll use the for just to return a sequence of those things you need to remove, then, after the for, you'll build a result
08:45mac__alright you've given me some ideas, I'm gonna try some stuff, will be back later. Thanks
08:59cemerickI saw the git mirror post on google groups -- FWIW, I'm *very* glad Rich is using svn at this point.
09:00cemerickWe're idly watching mercurial bubble along, but really only because it's the only dvcs that has passable tooling in an environment we use (Netbeans).
09:05rhickeycemerick: exactly, I need something that works in IntelliJ
09:08Chouserhuh, that's interesting. Well, it seems to be svn is a dead-end, but I guess it'll take a while for the tools to ramp up for its replacement.
09:08ChouserI'm entirely content using git locally talking to the svn server.
09:10Chousers/seems to be/seems to me/
09:10rhickeymeredydd: hey
09:10meredyddrhickey: See the {bug/extremely obscure, undocumented and dangerous feature} report on the list this morning?
09:10rhickeymeredydd: fixed already
09:10meredyddsweet, thanks
09:11rhickeybut the 'feature' is still undocumented, might go away in the future
09:11meredyddyeah...that part makes me nervous
09:11meredyddI only discovered it because I accidentally forgot to type a couple of @s in crucial places
09:12cemerickI'm incapable of using a vcs without a solid UI front end these days. A good sync/changes UI is a godsend compared to command-line diffing.
09:12meredyddand, as long as it doesn't throw an error, the unit tests don't catch anything
09:12meredyddso if that's not something to be relied upon, any chance you could explicitly break it?
09:13meredydd(or provide some sort of switch? Seems OTT.)
09:13rhickeymeredydd: I haven't thought about it in a while, but if I do keep it I'll add the same capability to agents
09:14meredyddooh, that'd be nice too.
09:14rhickeyso the next step will either be to do that or remove it, but not break/flag it
09:14meredyddOkay, that's absolutely fine.
09:14meredydd(and when I said "break", I meant "remove")
09:15rhickeyI'll be in the refs/agents soon as I intend to add consistency functions
09:15rhickeyptional validation fns to be run on change of state
09:15cemerickI know I've seen a function that, given a coll, returns pairs containing one item from coll and an index....can't find it now...
09:15rhickeyoptional
09:15meredyddNice, rhickey...presumably just before a transaction commits?
09:16rhickeymeredydd: right
09:16meredyddThat would be awesome, yes.
09:16rhickeySo transactions will be ACI_
09:16rhickeyagents too
09:17meredyddWell, I saw a post this morning on the list about a web framework, which mentioned a transaction macro which adds the "D" too...
09:17rhickeymeredydd: without cooperation from the transaction infrastructure, I don't see how
09:18meredyddrhickey: That puzzled me, as well. I had assumed there were some undocumented hooks he was using.
09:18rhickeycemerick: I don't know of one in boot.clj, but is the collection a vector?
09:19meredyddBut if you're implementing generic pre-commit triggers which can abort a transaction, I'd imagine you can make a particular ref or agent 'D' very straightforwardly.
09:20rhickeymeredydd: to be determined
09:20rhickeythe focus is on validation
09:22meredyddFinally, have you considered adding some equivalent to my 'alter-map-val' to boot.clj?
09:22meredyddReading and then re-(assoc)-ing map and vector values when altering refs is a PITA
09:23rhickeymeredydd: heh, I've been waiting for people to start complaining about that...
09:23meredyddI've ended up doing:
09:24rhickeythe general issue is nested 'change', I foresee a macro like -> but that flows back, maybe <- ?
09:24meredydd(alter my-map-ref alter-map-val :key #(do...something))
09:24meredydd(it's a poorly-named fn, it doesn't alter a ref)
09:25meredyddLike (alter), I use (apply) to chain through the other arguments
09:25meredyddso you can do something like:
09:25rhickeybest to keep the altering separate, the need is a general one for functional nested map change
09:25meredydd(commute exam_marks alter-map-val "A-levels" alter-map-val "Meredydd Luff" + 5)
09:26meredyddIt doesn't do an alter - it just returns its second arg, applying the given fn and args to the value at the given key
09:27rhickeymeredydd: just thinking out loud
09:27meredydd(fn [map-val key alter-fn & args]
09:27meredydd (assoc map-val key (apply alter-fn (get map-val key) args))))
09:27meredyddAnyway, that's my version.
09:28meredydd(works for vectors too, of course - anyting (assoc)able)
09:29rhickeyinteresting, if a bit verbose
09:30meredyddAnd this is what I love about this language - it's created by a man who thinks that requiring one arg each for map and key is too verbose :)
09:30meredyddI'm sure you can do better - just wanted to plant an idea in your head (where it appears it had long since taken root)
09:31rhickeymeredydd: thinking more about the name alter-map-val than the fn/key pair idea, which is good
09:32Chouseralter-map-val is more tied to 'assoc' then 'alter'
09:32Chousermeredydd: I guess you already mentioned that.
09:35meredyddalthough (<-) had damn well better be a fn rather than a macro
09:35rhickeymeredydd: hmmm...
09:35meredyddelse you won't be able to pass it to itself
09:35rhickey?
09:35meredydd(or, more likely, pass it inside something else that's expecting a function)
09:35meredyddrhickey: Imagine my original "alter" comment
09:35rhickeyIt's symmetrical with ->
09:36meredyddrhickey: Uhh...is it?
09:36meredyddWhat are you expecting that to expand to?
09:36rhickeyleft as exercise for the reader for now :)
09:37cemerickrhickey: not necessarily -- just seq-able. I could have sworn I saw such a function. Anyways, here's what I was thinking of:
09:37cemerick(defn enumerate [coll]
09:37cemerick (map #(vector %1 %2) coll (iterate inc 0)))
09:37rhickeyjust my intuition, I haven't written it, but it would be a macro
09:37meredyddmy point is that it's not going to be as simple as the (->) macro
09:38meredyddbecause you have to use each argument twice: once to (get) the data, once to (assoc) it back onto the original collection
09:38meredyddso it's not going to be simply symmetrical to (->)
09:38rhickeymeredydd: still, the associative things are consistent, so doable
09:38meredyddOh, very much doable.
09:39rhickeymeredydd: the symmetry is in the idea, walk the chain of associations, but in this case fold the last expression back into the structure
09:39meredyddI'm just making a case that it won't be *so* similar to (->), in advance of asking you to make (<-) a fn instead
09:39meredyddmy reason being that you can then use (alter) on it
09:40rhickeywhat if the last call needs more args?
09:41meredyddOh, arse. I see your point.
09:41meredydd(alter exam_marks <- exam_marks "A-levels" "Meredydd Luff" (+ 5)) won't fly, because the + gets evaluated too early.
09:41meredyddBut equally, it gets cumbersome if you have to make the fn explicit, because you use up your #():
09:42meredydd(alter exam_marks #(<- "A-levels" "Meredydd Luff" #(...do something...)))
09:42rhickeyif <- ends up being a macro, a <-@ macro is no big deal
09:42cemerickah-ha -- my enumerate is seq-utils/indexed in clojure-contrib :-P
09:42meredydd(What would "<-@" be?)
09:42meredydd(auto-wrap with a (fn)?)
09:43rhickey(<-commute exam_marks "A-levels" "Meredydd Luff" (+ 5)) ?
09:44rhickey(<-alter exam_marks "A-levels" "Meredydd Luff" 42)
09:44meredyddHmm...something in me regards it as icky to special-case both <-commute and <-alter
09:45rhickeyoops, meant <-set
09:45meredyddand <-set, of course
09:45rhickeywell, then you'll have to repeat exam-marls
09:45rhickeymakrs
09:45rhickeymarks
09:46meredyddnot necessarily...you could do something like (warning, ugly alert):
09:46meredydd(some-macro-name alter exam_marks "A-levels" "Meredydd Luff" (+ 5))
09:47rhickeysure
09:47meredyddand that would work when substituting "set!" for "alter" and a value for (+ 5)
09:47rhickeygotta run
09:47meredyddok
09:47meredyddcya
14:53mac__rhickey_: solved that problem I had before with the nested loop. It was part of a bigger mess so it took me a while but the for expression helped. Ended up doing something like (for [a (range 5) b (range (+ a 1) 5)] ...) so that each combination occurrs only once. Thanks for the pointer :)
14:54rhickey_mac__: great!
14:55mac__and thanks for clojure by the way, I started trying to learn common lisp but clojure hits a much sweeter spot being more functional and concurrent
14:55rhickey_you're welcome
15:48cemerickrhickey_: we had a brief data-modeling discussion some weeks back, where I was fiddling with various ideas to make a class as transparently usable from java and from clojure as possible, while keeping implementation in clojure as much as possible. Just on the face of it, what would you think of a defstruct variation that used gen-class to generate PersistentStructMap subclasses that had accessor methods for each of the privileged keys?
16:25rhickey_cemerick: would the keys be mutable?
16:25cemerickrhickey_: No.
16:27rhickey_cemerick: it might be interesting
16:27cemerickYeah. I might give it a run next week. I'm under deadline for Friday, so all I've been able to do is think a bunch.
16:28cemerickI need to learn a little more about how the javabean mechanisms work, because I want the resulting classes to be bean-compatible (read-only)
16:29cemerick(ideally without blinding conforming to the getFoo convention :-/ )
16:29rhickey_cemerick: very easy to get if you follow the naming conventions
16:29rhickey_heh
16:29cemerickI *hate* getFoo.
16:30cemerickNo-arg foo should have always been the accessor, n-arg foo the setter.
16:30rhickey_well, if the fields are immutable you can make them public and just define the methods for JavaBeans' sake
16:31cemerickYeah, that's the fallback.
16:32rhickey_with BeanInfo you can do whatever mapping you want
16:32cemerickI think I can hang a beaninfo impl off of the gen-class class that will link things up to the simpler getters
16:32cemerickwell, there you go :-)
17:24meredyddhey
17:25meredyddIs there a canonical way to load a file from a resource, like generated classes do?
17:29meredyddaha, never mind. Found it in -contrib.