#clojure log - Jul 10 2008

The Joy of Clojure
Main Clojure site
Google Group
List of all logged dates

6:26 StartsWithK: hi

6:27 how can i get metadata associated with a function?

6:33 hoeck: StartsWithK: hi

6:33 StartsWithK: only symbols and collections support metadata

6:34 StartsWithK: if i type ^#'println i get metadata of println function or println symbol then?

6:35 i woule like to do something like, (defn get-meta [f] (meta (var f)))

6:36 but it dosn't work

6:49 hoeck: with (var f) you are accessing the metadata of a var named "f"

6:50 var is a special form, evaluated at compile-time

6:50 StartsWithK: i know, that is my problem, o would like to say (get-meta printf)

6:52 hoeck: (get-meta (var printf)) ?

6:53 StartsWithK: that works

6:53 so i can use #' shortcut

6:54 hoeck: but then you just renamed meta to get-meta

6:54 StartsWithK: but is there any way to remove it completely

6:55 its just a minimal example

6:55 it would be used more like

6:55 hoeck: i guess no, i think clojure does a statical lookup of vars

6:55 StartsWithK: (defn user [username] (println (str "Homepage of " username")))

6:56 (def views ["/user/<str:username>" user])

6:56 and then i can extract needed parts from request url, find names of arguments for user function and send them in that order

7:03 ok, i can live with #' prefix

7:03 any one tried clojure with osgi?

7:05 hoeck: how do you use metadata for that (just curious)?

7:05 i mean your former example

7:05 StartsWithK: there is arglists metadata associated with each function

7:06 hoeck: ahh, i see

7:06 StartsWithK: so i take (first) from that, turn names of arguments to strings and from map that hold exctracted parts of url i construct list that i use for (apply view args)

9:30 mac_: hello

9:31 I'm having a little problem with how to store a return value from a different thread...

9:33 I want something like a java future but more clojurey, is there a good techniqe for such a thing? I tried doing (let [r (ref nil)] (do-work (dosync (ref-set r (something))) r)) but r seems to retain it's original value?

9:33 do-work here does the next expression in a specific thread

9:36 hmm maybe I'm just checking it too fast? could be that it's not set yet..

9:38 hehe yeah that was it. Sorry to bother anyone with my stupidity :D just needed a little wait loop like the Future.get method to wait for it to complete ;)

9:43 Chouser: mac_: if you use an agent and (send), then you can use (await) in your main thread to collect the results.

9:43 or rather, to wait until the results are ready.

9:45 (let [r (agent nil)] (send r (fn [r2] (dowork) "newvalue")) (await r) (prn @r))

9:45 mac_: Yeah I know, what I did here is a bit re-inventing stuff but I have to please the java libs I'm using. Guess I could restructure things a bit but this works at least..

9:45 Chouser: note that the function you send to agent r has to return the value instead of setting a ref.

9:45 mac_: Oh you mean instead of the ref

9:46 Chouser: yeah.

9:46 mac_: Yeah that's a bit more idiomatic I suppose. Gonna try that

9:46 Chouser: I guess if you already have another thread and a communication mechanism you want to use, what you had might be necessary.

9:47 mac_: Yeah now I'm confusing myself. Of course that's why I had it the way it was hehe

9:47 I have a rendering thread that's always the same, like swing (except this is OpenGL) and I have to use that for loading images

9:48 But in that case, you think what I did was fine?

9:50 I'm pretty new to all this, got my summer vacation now so I'm trying to learn some clojure by making a small game :)

9:55 Chouser: since I have to use a specific thread I guess I'm keeping my solution then, thanks a bunch for the input though

10:15 Chouser: yep, if you need to have the task done in a particular thread, I don't think agents are going to help you at all. Carry on. :-)

10:28 cemerick: is there any circumstance in which loop *doesn't* bind sequentially?

10:29 or, I should say, any circumstance where it's not supposed to bind sequentially?

10:36 Chouser: When you use recur, the values are bound in parallel. Is that what you're asking?

10:38 cemerick: Chouser: No...I've got a loop form that won't compile, indicating that one of the previously-bound symbols is unavailable in that context. Something like (loop [x (foo) y (bar) z (baz x y)] ...), and it's complaining about the usage of x and y as arguments to baz.

10:38 I've not been able to replicate it in a simple case, though.

10:39 Chouser: baz isn't a macro or something, is it? ought to still work, though.

10:39 cemerick: Nope, baz is a very simple helper fn.

10:40 Chouser: how big is your non-simple case? :-) pastable?

10:41 cemerick: Chouser: I'll see if I can whittle it down, and rip out some of the irrelevant details.

10:46 lisppaste8: cemerick pasted "loop not binding sequentially" at http://paste.lisp.org/display/63499

10:46 cemerick: If you remove the last binding in the loop (the list destructuring, then foo compiles OK.

10:48 Chouser: nice

10:49 cemerick: I always feel like I'm doing something wrong if I start thinking I'm hitting a compiler bug, but I think this is a legit example. Someone please smack some sense into me before I post it to the google group. :-)

10:49 Chouser: I've looked at the destructuring code before, so let me poke at it a little.

10:50 macroexpand on your loop is looking ... odd

10:52 I'm pretty sure you've found a bug in the loop macro

10:54 lisppaste8: cemerick annotated #63499 with "much-simplified example" at http://paste.lisp.org/display/63499#1

10:55 Chouser: (loop [x 1 y x [a b] (foo)]) vs. (loop [x 1 y x])

10:55 cemerick: ah, the x's gensym isn't being used

10:56 Chouser: there's a big "if" in the loop macro, to try to detect if it needs to destructure or not. there's bug in there somewhere.

10:56 bbl.

11:32 cemerick: Chouser: I see what the problem is, and I've got a *very* partial fix, but I don't know what the best way is to bring it all the way.

12:53 Chouser: cemerick: I'm back. care to share?

13:01 this is really pretty tricky

13:01 (loop [[a b] [1 2] c a]) ought to work

13:04 cemerick: Chouser: Yes, it really does need to work. Pasting now.

13:05 lisppaste8: cemerick pasted "barely-helpful loop patch" at http://paste.lisp.org/display/63506

13:07 cemerick: The problem is that loop needs to retain the same "signature" as its literal bindings dictate, so it needs to rewrite destructuring(s) into a nested let. In the process, it gensyms binding names, but doesn't propagate those gensyms down into nested forms.

13:07 Chouser: yep. good summary.

13:08 but with the example I just gave, Im

13:08 I'm not even sure it's possible to solve using this approach.

13:08 cemerick: The "patch" I just pasted makes this work: (loop [x nil [y z] x] nil), but it doesn't help with (loop [x nil z (nil? x) [a b] x] nil), because the gensym for x doesn't get dropped into the (nil?) form.

13:09 I think loop needs to walk all of the value forms, and replace any symbols it finds with gensyms as defined as top-level bindings.

13:09 Chouser: and we don't really want a code-walker to go through all the value expressions looking for names to replace.

13:09 heh

13:09 cemerick: That gets super-tricky though.

13:10 Chouser: what if we wrap each value expression in a let that defines all the names given up to that point?

13:10 cemerick: There's really no other way to do it, short of changing how loop binding work (I think). However, getting that right without squashing rebindings in those nested forms would be a serious pain.

13:11 Chouser: actually, I think my idea might work. Here I'll just whip up a new macro. Give me 4 or 5 hours...

13:11 cemerick: whew. yeah, that might do it.

13:11 I'm in there now, I can take a whack.

13:12 Chouser: I should just let you. I have things I Ought to be doing.

13:12 but they're not as fun :-/

13:13 cemerick: Hrm, I don't know if this is fun, either. ;-) I'm not nearly 133t enough to be messing with stuff like this.

13:18 Chouser: let-destructuring in the loop's value expressions will only happen for the initial values. recur calls will fail, won't they?

13:19 oh, nm -- we'll still need an inner let to do the destructuring for the body of the loop. That will take care of recur calls.

13:20 The penalty here will be for initial values the destructuring may happen multiple times.

13:20 cemerick: Chouser: That's not my understanding...

13:20 Yeah. Not much of a penalty, but yeah.

13:21 Chouser: a small runtime cost that hopefully HotSpot can remove when its not needed.

13:21 cemerick: Actually, no, if this is done right, there won't be any unnecessary destructuring.

13:21 Chouser: hm

13:21 cemerick: The nested lets should just pull in the full collections that have been gensymed (?)

13:22 We're just aligning symbols, not setting up destructuring.

13:26 Chouser: I think (loop [[a b] [1 2] c a]) should become:

13:26 (loop* [G__1936 [1 2] G__1937 (clojure/let [[a b] G__1936] a)] (clojure/let [[a b] G__1936 c G__1937]))

13:32 Is there a function that does (subsets '[a b c d]) => [[a] [a b] [a b c] [a b c d]]

13:50 lisppaste8: Chouser annotated #63506 with "another loop-fix attempt" at http://paste.lisp.org/display/63506#1

13:50 Chouser: cemerick: I think that'll work. not very well tested yet.

13:56 cemerick: Chouser: Yes, I'm pretty sure that will work.

13:56 I was spending a lot of time, and almost have my version completed, but yours is much more concise.

13:59 Chouser: I really should have let you do it. Sorry I couldn't resist.

14:00 cemerick: Chouser: feh, what do I care? Your solution is cleaner anyway. :-)

14:00 Chouser: but see what I mean about the extra destructuring?

14:01 (loop-ch1 [[a b] [1 2] c a d a]) generates (let [[a b] ...] ...) three times, all of which will be run the first time into the loop

14:03 cemerick: ah, yes, I see it now.

14:04 Chouser: If the value to be destructured is side-effecting, that could be more than a performance problem.

14:04 Chouser: hm...

14:05 no, the value parts aren't repeated -- they always use a gensym bound ealier in the loop.

14:05 it's only the destructuring itself (vector accesses, hash lookup, etc.) that are repeated.

14:06 I think. :-)

14:06 cemerick: Yeah. See, I told you I was out of my depth. :-P

14:07 Chouser: by all means post that to the group. Hopefully Rich can test and merge it in semi-soon.

14:17 Chouser: done

14:18 subsets is a bad name for that function, but I haven't thought of anything better.

15:01 JamesIry: powerset http://en.wikipedia.org/wiki/Power_set

15:04 Chouser: well, that's not what it does though. From [1 2 3] I want [1] [1 2] and [1 2 3], but not [2 3] or [3].

15:05 it's more like "growing sets" or something. I kinda thought haskell had a builtin function for that, but I don't know Haskell well enough to even know how to look it up.

15:06 well, google to the rescue. Haskell calls it "inits"

15:08 JamesIry: Chouser: ah, I misunderstood

15:09 technically I think Haskell's inits would return [[][1][1 2][1 2 3]]

15:11 Nafai: JamesIry: Correct

15:11 Prelude Data.List> inits [1, 2, 3]

15:11 [[],[1],[1,2],[1,2,3]]

15:12 erochester: Chouser: would this do what you want? (reverse (take (count [1 2 3]) (iterate pop [1 2 3])))

15:13 JamesIry: Nafai, Chouser, I think Haskell's inits makes more sense because it's a total function - any sequence is a valid input. Chouser's variation would be undefined for empty sequences

15:15 Nafai: Right, haskell's inits just returns a list of an empty list with an empty list argument

15:20 Chouser: my use case might actually work better with haskell's version

15:20 erochester: nice! here's what I've got at the moment:

15:21 (defn subsets [s] (reduce #(conj %1 (conj (or (last %1) []) %2)) [] s))

15:24 erochester: iterate pop is genius. I was looking for a way to use iterate, but didn't think of that.

15:24 erochester: cool. yours actually seems more straightforward in some ways. more complicated in others.

15:25 i'd be interested in knowing if you find a better way to limit the output of iterate. the way i did it seemed messy.

15:27 Chouser: (take-while seq (iterate pop [1 2 3]))

15:27 but that makes it harder to go one-more to get inits-like behavior

15:28 erochester: excellent. that's much better (although you're right about going one further.)

15:29 although what i posted won't work for inits-like behavior either. it raises an exception when you try to do (pop [])

15:29 Chouser: huh. none of these are lazy, and iterate pop doesn't do what we want when passed a list.

15:31 erochester: no. that's true too. hmm. what you posted might be your best option.

15:34 Chouser: naw, it ought to be lazy.

15:34 JamesIry: Lazy would be best - then you could handle infinite sequences

15:37 I can't help but think something based on map would work

15:38 Each element of the input sequence would get mapped to a sequence that ended with that element

15:41 Chouser: (take 10 (map take (iterate inc 0) (repeat [1 2 3])))

15:42 but you can't count your seq without killing the laziness.

15:49 lisppaste8: erochester pasted "subsets with lazy-cons" at http://paste.lisp.org/display/63514

15:49 erochester: This won't win any points for being short or elegant, but I think this works for both vectors and lists, it includes [] (for inits behavior), and it's lazy. And it's ugly.

15:49 And did I mention, it's ugly?

15:50 Chouser: it does get the job done.

15:51 by using conj, each "inner" seq is a non-lazy vector. But that's probably fine since you had to calculate all the elements up the the one you're conjing already anyway.

15:52 erochester: I love how easy Clojure makes lazy sequences. I'd gotten used to that with Python, and then every time I went back to common lisp, I was banging my head against my desk.

15:52 You're right. Both about conj and about the assumption I was making that this would be all right.

15:52 Chouser: python does lazy sequences? I missed that somehow.

15:53 erochester: iterators/generators

15:53 Chouser: oh, right.

15:57 Nafai: Lazy sequences are really handy

16:01 lisppaste8: Chouser annotated #63514 with "fully-lazy inits" at http://paste.lisp.org/display/63514#1

16:01 Chouser: having to use lazy-cat is annoying.

16:01 and that might be even less efficient -- I don't know if it uses the same s every time, or if it will re-calculate things.

16:03 ok, it does not recalculate. so if I could just figure out how to make take-while go one step further and ditch lazy-cat...

16:13 lisppaste8: Chouser annotated #63514 with "is this any better? (inits)" at http://paste.lisp.org/display/63514#2

16:16 erochester: That seems to do it. But I can't decide which one I prefer.

16:18 Chouser: you could replace the map and take-while with a for, :while, and destructuring. ...still don't know if that's any better though.

16:19 erochester: Yeah. That's probably a question of what you're used to.

16:22 Chouser: doubtless if rhickey chooses to include an inits, he will produce yet another implementation, and probably with a better name too. :-)

16:22 erochester: lol.

16:26 I think I've come up with about the best I'm going to do. At least until I walk away from the keyboard.

16:26 Chouser: :-)

23:45 ungraspiness: exit

23:55 jgrant: back

Logging service provided by n01se.net