#clojure logs

2008-08-26

08:17dabdhi anyone knows if the video from the clojure and the semantic web meeting will be available?
09:42rhickey_dabd: I've been on vacation and haven't had a chance to look at the semantic web video yet
09:44dabdrhickey: ok thanks
14:36mbeauI'd like to simulate keyword parameters in a function; it seems that this is not directly supported in clojure so it seems that I should be able to easily do this myself
14:37mbeauone idea I had was to take the 'rest' parameter list and turn that into a hashmap - that gives me pretty much what I'm looking for
14:37mbeauhow can I take a list and convert that into a map?
14:37mbeauseems like it should be obvious, but I can't figure it out
14:38erochestertry this: (apply hash-map [:a 1 :b 2])
14:39mbeauok, thanks
14:40erochesterno problem.
15:33cemerick...it's too bad that stuff like map, reduce, etc., aren't functions on ASeq. That'd make Java a whole lot more sane.
15:35rhickeycemerick: if Java had closures
15:35rhickeythat implemented IFn :)
15:36rhickeyVar map = RT.var("clojure","map");
15:36rhickeymap.invoke(...);
15:36rhickeyClojure is definitely callable from Java
15:37cemerickyeah, I know I could do that -- I don't think this particular chunk of Java will be sticking around for long though, so I don't want to prod at it *too* much.
15:37cemerickI'd be happy enough to drop in anonymous AFn subclasses, really.
15:37cemerickDon't take the suggestion seriously, though -- just a side-effect of having a sizable Java codebase that has clojure stuff starting to filter in.
15:44lisppaste8Chouser pasted "starved transaction?" at http://paste.lisp.org/display/65898
15:45Chouserwhen the transaction in slow completes, you see ":show-returned" and then the function dead completes.
15:45rhickeyok
15:46ChouserHowever, as long as the fast transactions keep committing, slow keeps resetting and never seems to finish.
15:46rhickeyright
15:46rhickeywhat is your expectation?
15:46ChouserI was expecting some Magic to how up and fix my problem. :-)
15:46Chousersorry, brb...
15:46rhickeyI see
15:48blackdoghas anyone been thinking of a ruby gem like package system?
15:51cemerickrhickey: why is Delay no longer a fn? (sorry if I missed some prior discussion)
15:52rhickeycemerick: there is now a proper force, which is a no op if the arg isn't a delay
15:53ChouserI'm back. I was under the impression that at some point new transactions would be held up to allow a very old transaction to complete.
15:55cemerickrhickey: yeah, I saw that, and that's fine, but there are definite advantages to being able to treat delays as fn's
15:56rhickeyChouser: no, only if there is a live conflict will an older transaction 'win', your slow doesn't acquire anything until after its delay - try putting (ensure c) before sleep
15:58rhickeycemerick: I'm on the fence about how rich to make delays
15:58rhickeywhen would you use them as fns?
15:59cemerickanytime I have a map containing fns for values; some functions may be very involved, so caching their results transparently is super-handy
16:00cemerick(handy enough that I'd use my own fn-delay impl to get the same results, FWIW)
16:01rhickeycemerick: why wouldn't you just delay the invocation?
16:02rhickeythen force = call
16:03rhickeydelays as fns was always just sugar
16:03cemerickbecause I want to wrap up fns into a map and toss it over the wall to a caller -- I don't have control over when those functions are pulled out and invoked
16:04rhickeybut the caller doesn't pass args
16:04rhickeyso they could call force instead of invoke
16:04rhickeyor I'm confused about the use case
16:05cemericksure, but then they'd have to know about delays as well as fns -- I'd end up littering (if (delay? fn) (force fn) (fn)) all over the place.
16:05rhickeyno - force does that for you
16:06cemerickso you're suggesting making all of the values in such maps delays?
16:06rhickeyno, force on non-delay just works
16:06rhickeyuser=> (force 42)
16:06rhickey42
16:07rhickeyFrom Java, Delay.force(42)
16:07cemerickoh, I see; my initial reaction to that is "yuck"
16:09cemerickI guess I don't see the advantage of having a split between fns and delays to begin with; using (force fn) all the time instead of simply (fn) isn't obviously better
16:09rhickeyyes it is - because you can't say (42)
16:10rhickeynow you can have mixed delayed and non-delayed values in a mixed environment and handle uniformly
16:14rhickeybut (d) was just sugar for (get d), no difference in behavior
16:17cemerickthe problem with that is that forcing a fn returns the fn, not the value of invoking the fn; a mixed environment of delays and fns doesn't yield the results I'd expect in that case (not that those results are incorrect, just not what I'd expect). I view delays as essentially transparent wrappers around fns, so treating them as values themselves trips me up.
16:17cemerickI suppose my perspective could be fundamentally faulty *shrug*
16:19rhickeydelays delay expressions, the fact that they are implemented using closures is an implementation detail - you could always have said (delay 42) - where's the fn in that? :)
16:20cemericktouch� :-) Of course, any (delay x), where x is already a strict value, doesn't really have any application (that I can think of).
16:22rhickeyeven when not a constant, it's still an expression that's delayed, not a fn: (delay (+ 21 21))
16:23cemericksure
16:23rhickeybut without force that detects delays, people did/do have to say (delay 42) sometimes when creating a data structure with mixed delayed/non-delayed values. Now they don't have to
16:25cemerickI'd *much* rather put the onus on the creator of the data structure, and not the caller.
16:26rhickeythere is always some onus on the caller, since there isn't a value without force/get/call
16:27cemericksurely fn invocation is more fundamental than force/get, certainly in the overwhelmingly common cases?
16:27rhickeypretending all the values are fns doesn't change that
16:28rhickeyand it precludes uniform handling
16:28rhickeythat's the key point
16:31cemerickI guess we have different common use-cases in mind. Doing (force x) and then conditionally invoking the result seems pretty backwards to me, but then I can't think of the last time I put delays and numbers (for example) into the same map or list.
16:32cemerickMy final point would be: why not permit the old behaviour? Delays-as-fns is sugar, for sure, but makes things a lot simpler (in my use cases, anyway).
16:32rhickey> Doing (force x) and then conditionally invoking the result - I don't see when that happens ever. force is the exact same operation as call was, except it works on non-delays too
16:34rhickeyinvoke called get(), force calls get()
16:35rhickeyiff it's a delay
16:35cemerickthe problem is this; consider a vector: (def v [(fn [] 5) (delay 5)])
16:36cemerick(map force v) => (user.fn__2127@1c2812 5)
16:37cemerickif delays are fn's, you can do (map #(%) v) => (5 5)
16:38cemerickthat's what I mean by conditionally invoking the result -- that fn is its own value which then needs to be invoked after being forced in order to get to the same place
16:40rhickeyyour example has no purpose to using delay, so it's hard to see the point
16:41rhickeyif the second 5 is some expensive expression, then (def v [5 (delay 5)])
16:42cemerickyes, it's watered down to make an example; consider {:root root-node :size (delay (fn [] ....))}, a tree structure with a :size attribute that will walk the tree and return and cache the size of the tree rooted at root-node. You want the value of :size to be a fn, so it can be optionally delayed depending upon the specific costs associated with the size calculation.
16:43rhickeythen it's not (delay (fn [] ...) but (delay ...)
16:44cemerickright, sorry -- the point's the same, though
16:44rhickeyno it's not, once you have an expression, then fns have nothing to do with it
16:46rhickeyall delays-as-fns do is superficial, and if you've been wrapping values in fns to make them match delays you'll no onger have to
16:46rhickeylonger
16:47rhickeycheck the diff on Delay.java - it's not functionally different
16:47cemerickyeah, I'm looking at it right now; no longer being an AFn is a significant difference
16:48rhickeynot in what happens during invoke/force or the nature of delayed values
16:49cemerickyou can't invoke a delay any more -- that's quite different, implementation detail or not
16:50cemerickyeah, I mistyped the (delay (fn []...)) bit -- I meant (delay ...)
16:51rhickeythe reason I took out delays as fns and delays as IRef is that they do not have the same behavior when the contained _value_ is itself a fn, e.g. invoking a var casts its value to fn and invokes it, but a delay didn't do that
16:56cemerickI don't currently use refs much (if at all); I wouldn't think that their requirements are tied to delays, though.
16:56rhickeycemerick: delays really aren't functions of anything, not taking args makes that plain
16:57rhickeyI understand it's a breaking change for you, and I'm sorry about that, but I made delay public to help you along and have subsequently refined its design - I've got to be able to do that between releases
16:58rhickeyuniform force is plainly a better interface than invocation
16:58cemerickoh, no need to apologize, please :-)
17:00rhickeybut there is a transformation between what you've been doing and the new way, that is easier on the producer side and, let's say different on the consumer side, but strictly more powerful even if you don't currently leverage that
17:06ChouserI guess what bothers me about my starved transaction is that I could have a large system that's functioning just fine, but by adding some new code that innocently pokes away too quickly at a ref, I could cause some existing slow transaction to start hanging for long stretches at a time.
17:07ChouserI suppose you'd just have to test for that and fix your slow transactions -- split them up, add ensure, or whatever?
17:09rhickeyChouser: that's not a problem I can solve for you. There will always be issues with contention that are part of a concurrent design. STM and agents handle the correctness part, but you will still have to deal with transaction granularity, degree of overlap, transaction duration etc.
17:10rhickeyone general rule is not to have long-running transactions compete with short running transactions for the same refs
17:11rhickey(writing)
17:15rhickeyChouser: did you try the ensure before sleep?
17:16Chouseryep, wokred like a charm
17:16rhickeyso you do have some tools to work with
17:16Chouseryes
17:17cemerickrhickey: thanks for clarifying things earlier; I hope I didn't come off as irritated or whatever...
17:18rhickeynp, I understand it sucks to have something changed from underneath you
17:18cemericknah, it's to be expected when you're running off of HEAD :-D
17:19cemerickbesides, nothing will change much; I expect I'll create my own DelayFn class (or whatever) to retain the same behaviour for myself. Oh, the joys of interfaces...
17:21cemerickalso besides, such things are a very, very small price to pay to be able to use something as truly phenomenal as clojure
17:21rhickeyChouser: I meant 'can solve for you automatically' before, of course I'm always willing to help you
17:22Chouserrhickey: heh, I understood.
21:12jamiihow does clojure find namespaces when refer is used? do I have to load the file first?
21:13Chouseryes, refer only works with names that have already been loaded
21:27Chouser(apply concat (partition 1 2 [1 2 3 4 5])) => (1 3 5)
21:27Chouserbut there's got to be a better way, right?
22:22arohnerI'm finding myself doing
22:23arohner(let [foo (assoc foo key val)]...)
22:23rhickeyuser=> (take-nth 2 [1 2 3 4 5])
22:23rhickey(1 3 5)
22:23arohnerthat doesn't feel idiomatic
22:23arohneris there a better way to accomplish that?
22:25rhickeyarohner: what feels wrong - reusing foo?
22:25arohneryeah
22:25rhickeyyou could call it bar :)
22:25arohnerhah
22:25arohnerI'm immediately recurring on foo
22:25arohnerso for more context
22:25arohner(let [foo (assoc foo key val)] (recur foo))
22:26arohnerbut it still feels slightly weird
22:26rhickeythe first foo is in a loop?
22:26arohneryes
22:27rhickeyI'd just (recur (assoc foo key val))
22:27arohnerok, I guess that makes it idiomatic :-)
22:28arohnerhmm, maybe that's not the source of my hesitation
22:28rhickeybut consider reduce
22:28arohnerah
22:28arohnermaybe that's what I'm looking for
22:29arohnerI didn't think of treating the problem that way, but that might be a better fit
22:30arohnerthanks
22:32rhickeysure
22:36Chouserrhickey: take-nth. I feel dumb now.
22:37rhickeyChouser: don't worry - I had to look it up myself :)
22:37Chouserarohner: and if you're using reduce to build a map, you might like into
22:38rhickeyyes, if you are not doing any other logic
22:38arohnerwhat does conjoined mean in this context?
22:39rhickeyuser=> (conj {} [:a 1])
22:39rhickey{:a 1}
22:39rhickeyuser=> (conj {} [:a 1] [:b 2])
22:39rhickey{:b 2, :a 1}
22:40arohnerah, that conjoined :-)
22:40rhickeymaps are collections of entries, so you can conjoin an entry
22:41rhickeyor another map:
22:41rhickeyuser=> (conj {:a 1} {:b 2 :c 3})
22:41rhickey{:c 3, :b 2, :a 1}
22:42rhickeyClojure is like Lego
22:42arohnerhah
22:42arohnerthat wouldn't be a bad irc topic
23:00arohnerare there any functions for working with ratios?
23:01arohneri.e. get the numerator, get the denominator, increment the fraction?
23:03rhickey(.numerator 22/7)
23:04rhickeyand .denominator
23:04arohnerah, cool
23:05Chouserhuh. Why don't I see those with (doseq x (.getMethods (class 3/4)) (prn x))
23:06rhickeybecause they are fields
23:06Chouserah
23:06rhickeypublic final
23:06arohnerChouser: that is a cool trick
23:07arohnerand yet again clojure is a better java than java
23:07arohnernot to say that's only what it's good for!
23:08Chouserarohner: one of the tricks I use to give the impression I know things when I don't.