#clojure log - Apr 09 2008

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

10:06 Chouser: Shouldn't (binding [x 5] x) just return 5?

10:09 drewr: It does for me.

10:09 user> (def x 1)

10:09 #<Var: user/x>

10:09 user> (binding [x 5] x)

10:09 5

10:10 Chouser: oh! you have to def it first.

10:11 I think I used to know that. Thanks!

10:12 drewr: What I don't understand is why you can't just use let.

10:12 Chouser: you can, but they do different things.

10:12 let is lexical. you can use x inside the syntactic boundaries of the (let ...)

10:12 bindings survive through function calls.

10:12 "dynamic binding" I think it's called.

10:13 (defn prnx [] (prn x))

10:14 (binding [x 5] (prnx)) --> prints 5

10:14 (let [x 5] (prnx)) --> crashes, because x is not defined in prnx

10:14 cgrand: chouser: dynamic scoping

10:14 Chouser: cgrand: thanks.

10:14 rhickey: both correct

10:16 cgrand: rhickey: thanks

10:16 Chouser: so shouldn't this work? (binding [x 5] (for [i [1 2]] [i x]))

10:16 drewr: Chouser: The first defn won't succeed though.

10:16 Chouser: drewr: you still have to do a (def x) earlier, like you showed me.

10:19 does that binding...for crash for anyone else?

10:20 drewr: OK, looking at the definitions of print and println helps me understand how that's useful.

10:24 rhickey: Chouser: crash?

10:24 abrooks: I think he meant took an exception.

10:24 Chouser: well, an exception. java.lang.IllegalStateException: Var x is unbound.

10:24 sorry. sloppy use of English.

10:24 rhickey: remember for is lazy, better consume it all before the binding goes out of scope

10:25 Chouser: oh! weird...

10:25 a closure doesn't hang onto its dynamic scope?

10:25 abrooks: Chouser: That one agin... :)

10:25 rhickey: the seq is outliving the binding

10:25 abrooks: rhickey: Is the best way to (doall (for ....)) ?

10:25 rhickey: closure == lexical scope, bdingind == dynamic scope, so no

10:25 binding

10:26 Chouser: abrooks: I didn't realize this was the problem you were having.

10:26 abrooks: abrooks: That was the issue the other night. Look at the noise.log.

10:26 Chouser: abrooks: yeah, I thought I understood at the time, but apparently I didn't.

10:26 rhickey: abrooks: dorun or doall, depending on if it's all side effects or you want to retain the seq

10:28 abrooks: rhickey: The other night I got bitten by lazy for when I stuck it inside a (do ..) because I wanted for for sideffects (sending agents functions) but wanted the form to have a different value. The do allowed the for to be lazy. I then put a (doall ) in and it worked but only after I figured it out.

10:29 Should non-terminal slots in do be eager?

10:30 rhickey: abrooks: no

10:30 abrooks: Hm. For my own understanding, why? :)

10:30 Or why not, actually.

10:30 rhickey: I do think 'for' implies iteration for people though, so this is a common mistake

10:31 abrooks: Yes. The imperative meme has clamped onto all of our brainstems and is quite embedded.

10:31 Chouser: FWIW, I'm fine with a 'for' being lazy, it was the behavior of binding and closure that threw me.

10:31 rhickey: abrooks: there's not really a notion of a terminal slot, they all move together like an odometer

10:32 Chouser: items in 'do' are sequential, aren't they?

10:32 abrooks: rhickey: In a (do ..)?

10:32 I thought they were as Chouser said.

10:33 rhickey: abrooks: I thought you meant for, there's no laziness in do

10:34 abrooks: rhickey: (do ) allows for to be lazy.

10:34 rhickey: abrooks: for is always lazy

10:34 abrooks: (do (for [x (range 10)] (println x)) 9)

10:35 rhickey: I'm probably not saying this right.

10:35 If I remove the 9 in the above, (do ) consumes all of the for. In the non-terminal slot, it doesn't.

10:36 rhickey: abrooks: no, the repl is what consumes the for, in printing the result

10:36 abrooks: (do (for [x (range 10)] (println x)))

10:36 rhickey: (def x (do (for [x (range 10)] (println x))))

10:36 x

10:37 abrooks: Ah. And in the general case, /something/ is consuming the last value of (do ).

10:37 rhickey: maybe

10:38 abrooks: The sticking point for me is that the values of other slots of do are thrown away and are never consumed, right?

10:38 rhickey: right, do is for side effects

10:38 abrooks: So if do is for side effects then should it be eager?

10:38 At least for non-terminal slots?

10:39 ^should it^shouldn't it

10:39 rhickey: (do (foo) (bar) (baz))

10:39 * abrooks needs more tea.

10:39 rhickey: how does do know if foo returns a lazy seq that needs forcing?

10:40 abrooks: Should I not be using (for ) for iteration or should I always wrap (doall ) around it when using it in a non-terminal (do ) slot?

10:40 drewr: rhickey: What's the reason for Clojure being case-sensitive? I always thought it was considered a feature of Lisps to write lowercase, but refer to code with uppercase.

10:40 rhickey: Chouser: you can use a dynamic value in an expression that returns a lazy seq by capturing it:

10:41 drewr: For example, this conversation would be much clearer if we could write DOALL, FOR, etc.

10:41 rhickey: (def x 1)

10:41 user=> (binding [x 5] (for [i [1 2]] [i x]))

10:41 ([1 5] [2 1])

10:41 user=> (binding [x 5] (let [x x] (for [i [1 2]] [i x])))

10:41 ([1 5] [2 5])

10:42 abrooks: drewr: I'm case insensitive. I was born that way. The doctors think it's my brain not my eyes.

10:42 rhickey: drewr: I consider CL's treatment of case a major misfeature

10:43 drewr: rhickey: Scheme is case-insensitive too.

10:43 * abrooks actually prefers case sensitivity and would be frustrated if he had to type in upper-case.

10:43 drewr: abrooks: That's an argument for case-insensitivity. :-)

10:43 abrooks: drewr: In conversation it can be fine (and clear) to type bare language constructs upper-case.

10:45 drewr: I think the best argument for case sensitivity is that it forces other people's code to look the same.

10:45 rhickey: case insensitivity is information-lossy

10:45 can be a huge problem when identifiers have to go through Lisp in/out of the outside world

10:45 think about Clojure's java interop

10:47 drewr: That's what I was trying to get to. I wanted to know if it was purely subjective, or if you had a technical reason. When you're interoperating with case-sensitive symbols from a host lang, it would probably be a nightmare to allow arbitrary case.

10:47 I buy that.

10:48 Although, as a personal preference, I tend to like CL and Scheme's case agnosticism.

10:48 rhickey: heh - one of my number one problems with CL

10:51 jteo: imho, worth the price for java interop.

10:51 drewr: jteo: Yeah, I agree.

10:53 I can see how ambiguity in case can lead to maintenance catastrophes in large codebases (I've never written anything big enough in Lisp to have an issue).

10:53 rhickey: I simply think it's wrong for the user to enter x and the system to change it to X, so ascii, so 1970s...

10:54 greatly reduces the utility of symbols

10:55 java interop/natural language/xml

10:56 jteo: minor nitpick: i'm confused by the use of "[ ]". :)

10:56 rhickey: confused in what way?

10:57 jteo: as opposed to common lisp, where you would only ever see "( )" encompass variables.

10:58 rhickey: I find Clojure much easier to read than CL

10:59 jteo: i admit i might be biased having just wrapped my head around CL.

10:59 ;)

10:59 rhickey: some Scheme's have adopted the use of [], by convention, to distinguish data lists from code lists

11:00 drewr: Aren't they synonomous with () though? I thought it was just convention.

11:00 rhickey: Yes, I did say by convention

11:00 drewr: Sorry, read too fast.

11:01 rhickey: but the reading experience is similar, although Clojure's [] are vectors

11:01 I haven't had anyone ask to go back to parens for everything :)

11:02 jteo: true. i'll get used to it i suppose.

11:04 Chouser: I really really like the use of []. I think that tiny little adjustment might be part of why I have found Clojure to be so much easier to read than other lisps.

11:04 Or perhaps I've just reached some kind of critical mass in my lisp experience. ;-)

11:04 rhickey: thanks for the binding capture hint.

11:09 rhickey: Concurrency talk video is up: http://clojure.blip.tv/file/812787

11:13 drewr: rhickey: Thanks for sharing these talks with the world. I've found them very helpful.

11:13 rhickey: you're welcome

12:13 Chouser: abrooks: many times when you would use 'for' and want side-effects you might be better off with 'doseq'

12:15 * rhickey considering dofor

12:18 Chouser: would that replace doseq?

12:18 rhickey: no, would replace (dorun (for ...

12:19 * Chouser nods

12:20 rhickey: or maybe doseq with [] would be that, e.g. (doseq [...] == (dorun (for [...]

12:20 e.g. add list comprehensions to doseq

12:20 Chouser: yeah, that's what I was driving at.

12:22 cgrand: how would you doseq over a map then? (doseq [k v]...

12:22 rhickey: hmmm... couldn't determine if doseq [...] xs exprs was list comprehension or destructuring...

12:22 :)

12:22 cgrand: :-)

12:23 * rhickey better think about this over lunch

12:50 rhickey: doseqs

12:57 Chouser: sure!

12:58 rhickey: 'for' could be 'from' to avoid confusing people...

12:59 and better imply sequence vs. iteration

13:00 jteo: umm, newbie question: what is the exact definition of a 'binding form'?

13:03 rhickey: fn parameter or first half of a let binding

13:03 contains symbols that will be bound to values

13:04 simplest binding form is a symbol

13:04 jteo: thanks! :)

13:05 Chouser: with the clarity of [] in doseqs for the cost of just two keystrokes, I

13:05 rhickey: but vectors and maps can be binding forms too, containing symbols that will be bound to parts of the value n a process called destructuring

13:05 Chouser: ...I'll probably stop using doseq

13:06 rhickey: hmm...

13:07 Chouser: and for what it's worth, I think I'd prefer 'for' over 'from'.

13:08 rhickey: Chouser: I did too, but I get a lot of people thinking it's iteration/loop

13:08 * abrooks comes back after lunch and sees Good Things happening. :)

13:09 abrooks: I like where this conversation is going.

13:10 Chouser: I can see that as a problem, but 'from' strikes me as weak solution.

13:10 I guess if 'for' has inaccurate connotations, picking something that has no connotations at all /might/ be better.

13:11 rhickey: what are the connotations of from that conflict?

13:11 abrooks: (comprehend ...) Hm. No.

13:12 rhickey: The verb is implied in either case, but I think people read/infer for...do and from...take

13:13 Chouser: I just meant 'from' has no specific connotations, which does help me understand when first reading it, but doesn't mislead me either.

13:13 does *not* help me understand...

13:13 bleh

13:13 I just meant 'from' has no specific connotations, which doesn't help me understand when first reading it, but doesn't mislead me either.

13:14 abrooks: seq-from?

13:14 Chouser: ew

13:14 lazy-for?

13:15 abrooks: lazy-ass? (lazy assignment :)

13:19 I kind of like lazy-for. It explicitly puts it in the class of lazy-cons and lazy-cat.

13:19 rhickey: 'from' has connotations from SQL for anyone that's used a db

13:19 abrooks: The current (for ) could be eager matching peoples expectations of iteration.

13:20 rhickey: abrooks: lazy in lazy-cons/lazy-cat refers to the evaluation of the arguments, not the laziness of the result, else most of the seq library would be lazy-this/lazy-that

13:21 abrooks: I'm trying to make all side-effect ops begin with do

13:22 Chouser: SQL's 'from' doesn't have :when or :while. I guess SQL's 'where' is like clojure/for's :when...

13:22 abrooks: do-for (dofor looks dumb).

13:22 Chouser: rhickey already named that doseqs

13:23 abrooks: And doseqs would have the decomposing bindings []?

13:23 * abrooks scrolls up ...

13:23 Chouser: abrooks: yes

13:23 abrooks: destructuring not decomposing.

13:24 rhickey: doseqs would have for syntax

13:24 doseq already does destructuring

13:28 abrooks: Hm. (doseqs ) doesn't do it for me name-wise. It's more like (for ) than (doseq ). It's the notions of (for ) and (do* ). Just a thought.

13:30 Chouser: So 'doseqs' could replace (doall (for ...)) and (doseq ...), and 'from' could replace 'for'.

13:31 abrooks: Oh, if doseqs would subsume doseq I don't have a problem with it. The above plan sounds pretty appealing.

13:32 Chouser: well, when I suggested doseq going away, rhickey said only "hmm..."

13:34 abrooks: Why not just add the syntax to doseq?

13:34 * abrooks tires to think if the additional syntax would be incompatible.

13:34 abrooks: er... ^tires^tries

13:34 I am tired, though.

13:34 More tea.

13:35 Chouser: abrooks: yes, the syntax would be incompatible.

13:38 (doseq [w x] y z) <-- is [w x] a binding form for y, or is w binding x (with y and z making up the body)?

13:38 (doseqs [[w x] y] z) vs. (doseqs [w x] y z)

13:49 'from' and 'doseqs' would have very different names considering the similarity of their syntax.

13:51 cgrand: I'd like to submit this channel for archiving to Arkivo http://irclog.turbogears.org/ Are you okay with that?

13:53 Chouser: I can't see anything other than the last 100 messages. Am I doing something wrong?

13:54 cgrand: chouser: the little non-obvious green tab "Browse Archive"

13:54 Chouser: yeah, but even there I only see today's date?

13:54 oh, some of them go back farther.

13:55 cgrand: chouser: indeed

13:55 is there another public irc archiving service?

13:56 abrooks: cgrand: None. None that Chouser knows of. [hairy eyeball at Chouser]

13:56 cgrand: (modifying the url by hand is not so fun)

13:58 Chouser: oh, if it's just a UI thing, I imagine they'll fix it.

13:59 abrooks: Chouser: Actually, I realized that there's work that would need to be done to otto and noiselog before they would really be usable outside of a #noise environment.

13:59 rhickey: cgrand: archiving would be great

13:59 Chouser: abrooks: yes. more than starting from scratch, perhaps.

14:01 abrooks: irclog.org might be a solution.

14:03 Chouser: If someone has a Java server environment they could lend, we could write a solution in Clojure.

14:03 abrooks: Oh, right, I forgot you finished noiski. :)

16:16 drewr: I'm having trouble figuring out where clojure/seq is having a problem: http://paste.lisp.org/display/58904

16:17 (I'm adapting the spelling corrector to work with recent clojure.)

16:18 I isolated that snippet out of the edits1 function.

16:21 Ah, it looks like I hadn't restarted my JVM since updating my working copy.

16:26 Chouser: is it working now?

16:27 drewr: Yeah, it works. I ended up only having to change two FOR invocations.

16:27 ...to use :when.

16:27 Should I update the wiki even though this probably won't work with the released version?

16:31 Better not since the old definition is what's documented in the published API.

16:33 Chouser: You could add a comment to the end, so it'll be easy to update after the next release.

16:37 ok, I need Java help. how best to do sprintf of "%d:%02d"?

16:45 (defn fmt [h m] (str h ":" (. (new java.text.DecimalFormat "00") format m)))

16:50 (. java.text.MessageFormat format "{0,number,0}:{1,number,00}" (to-array [1,5]))

16:51 drewr: Take a look at Arto's impl.

16:51 * drewr looks for link

16:51 drewr: http://svn.bendiken.net/clojure/util.clj

16:52 Chouser: thanks

17:31 drewr: What did EQL? turn into?

17:32 rhickey: =

17:32 drewr: Ah.

17:38 * drewr out

20:17 Modius: Do clojure's functions have any form of TailCallOptimization?

20:19 Chouser: Modius: no, but you can use the 'recur' form to manually achieve the same performance.

20:20 Modius: Is that a code-walking macro basically?

20:20 Converting the code to cps form?

20:20 Chouser: no, I don't think so.

20:20 recur is a bit like a tail-call-optimised function call to the enclosing function (or 'loop')

20:22 See 'recur' on this page: http://clojure.sourceforge.net/reference/special_forms.html

20:31 If I know I'm going to loop through an entire seq several times

20:31 ...it probably makes sense to force it to be computed once.

20:33 Is 'doall' the right way to do that, even though there are no side-effects involved?

21:16 Is 'doall' the right way "pre-fetch" a lazy seq's values, even if there are no side-effects involved?

21:19 rhickey: it's a way, why would you need to do that?

21:28 Chouser: If I know I'm going to loop through an entire seq several times, and I think it'll be cheaper to use the values than to recompute them.

21:30 oh, or does FnSeq cache the results automatically?

21:30 rhickey: yes it does

21:31 Chouser: I'm sorry, it's even documented. I'll go away now.

Logging service provided by n01se.net