2008-04-09
| 10:06 | Chouser | Shouldn't (binding [x 5] x) just return 5? |
| 10:09 | drewr | It does for me. |
| 10:09 | drewr | user> (def x 1) |
| 10:09 | drewr | #<Var: user/x> |
| 10:09 | drewr | user> (binding [x 5] x) |
| 10:09 | drewr | 5 |
| 10:10 | Chouser | oh! you have to def it first. |
| 10:11 | Chouser | 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 | Chouser | let is lexical. you can use x inside the syntactic boundaries of the (let ...) |
| 10:12 | Chouser | bindings survive through function calls. |
| 10:12 | Chouser | "dynamic binding" I think it's called. |
| 10:13 | Chouser | (defn prnx [] (prn x)) |
| 10:14 | Chouser | (binding [x 5] (prnx)) --> prints 5 |
| 10:14 | Chouser | (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 | Chouser | 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 | Chouser | 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 | Chouser | 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 | rhickey | 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 | abrooks | Should non-terminal slots in do be eager? |
| 10:30 | rhickey | abrooks: no |
| 10:30 | abrooks | Hm. For my own understanding, why? :) |
| 10:30 | abrooks | 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 | abrooks | 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 | abrooks | rhickey: I'm probably not saying this right. |
| 10:35 | abrooks | 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 | rhickey | 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 | abrooks | At least for non-terminal slots? |
| 10:39 | abrooks | ^should it^shouldn't it |
| 10:39 | rhickey | (do (foo) (bar) (baz)) |
| 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 | rhickey | user=> (binding [x 5] (for [i [1 2]] [i x])) |
| 10:41 | rhickey | ([1 5] [2 1]) |
| 10:41 | rhickey | user=> (binding [x 5] (let [x x] (for [i [1 2]] [i x]))) |
| 10:41 | rhickey | ([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 | 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 | abrooks | 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 | rhickey | can be a huge problem when identifiers have to go through Lisp in/out of the outside world |
| 10:45 | rhickey | 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 | drewr | I buy that. |
| 10:48 | drewr | 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 | drewr | 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 | rhickey | greatly reduces the utility of symbols |
| 10:55 | rhickey | 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 | jteo | ;) |
| 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 | rhickey | 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 | Chouser | Or perhaps I've just reached some kind of critical mass in my lisp experience. ;-) |
| 11:04 | Chouser | 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:18 | Chouser | would that replace doseq? |
| 12:18 | rhickey | no, would replace (dorun (for ... |
| 12:20 | rhickey | or maybe doseq with [] would be that, e.g. (doseq [...] == (dorun (for [...] |
| 12:20 | rhickey | 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 | rhickey | :) |
| 12:22 | cgrand | :-) |
| 12:50 | rhickey | doseqs |
| 12:57 | Chouser | sure! |
| 12:58 | rhickey | 'for' could be 'from' to avoid confusing people... |
| 12:59 | rhickey | 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 | rhickey | contains symbols that will be bound to values |
| 13:04 | rhickey | 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: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 | Chouser | 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 | Chouser | does *not* help me understand... |
| 13:13 | Chouser | bleh |
| 13:13 | Chouser | 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 | Chouser | lazy-for? |
| 13:15 | abrooks | lazy-ass? (lazy assignment :) |
| 13:19 | abrooks | 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 | rhickey | 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 | Chouser | abrooks: yes |
| 13:23 | abrooks | destructuring not decomposing. |
| 13:24 | rhickey | doseqs would have for syntax |
| 13:24 | rhickey | 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 | er... ^tires^tries |
| 13:34 | abrooks | I am tired, though. |
| 13:34 | abrooks | More tea. |
| 13:35 | Chouser | abrooks: yes, the syntax would be incompatible. |
| 13:38 | Chouser | (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 | Chouser | (doseqs [[w x] y] z) vs. (doseqs [w x] y z) |
| 13:49 | Chouser | '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 | Chouser | oh, some of them go back farther. |
| 13:55 | cgrand | chouser: indeed |
| 13:55 | cgrand | 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 | drewr | (I'm adapting the spelling corrector to work with recent clojure.) |
| 16:18 | drewr | I isolated that snippet out of the edits1 function. |
| 16:21 | drewr | 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 | drewr | ...to use :when. |
| 16:27 | drewr | Should I update the wiki even though this probably won't work with the released version? |
| 16:31 | drewr | 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 | Chouser | ok, I need Java help. how best to do sprintf of "%d:%02d"? |
| 16:45 | Chouser | (defn fmt [h m] (str h ":" (. (new java.text.DecimalFormat "00") format m))) |
| 16:50 | Chouser | (. 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 | 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. |
| 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 | Modius | Converting the code to cps form? |
| 20:20 | Chouser | no, I don't think so. |
| 20:20 | Chouser | recur is a bit like a tail-call-optimised function call to the enclosing function (or 'loop') |
| 20:22 | Chouser | See 'recur' on this page: http://clojure.sourceforge.net/reference/special_forms.html |
| 20:31 | Chouser | If I know I'm going to loop through an entire seq several times |
| 20:31 | Chouser | ...it probably makes sense to force it to be computed once. |
| 20:33 | Chouser | Is 'doall' the right way to do that, even though there are no side-effects involved? |
| 21:16 | Chouser | 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 | Chouser | 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. |