#clojure log - Nov 06 2008

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

1:23 Cark: hello

4:50 kib2: hi, did someone read the first chapters and is it worth a look ? http://blog.thinkrelevance.com/2008/11/5/clojure-beta-book-available

6:20 tomppa: hmm, AWT/Java2d seems to produce an awful lot of garbage. At first I thought it was Clojure but luckily it seems that wasn't the case.

6:24 ah damn. It was the Clojure side after.. forgot the laziness part in my benchmark

6:33 Lau_of_DK: tomppa, garbage ?

6:34 tomppa: I'm doing some simple performance tests and I get lots of annoying gc pauses

6:34 part of it is probably because of awt but I have tried to factor that out

6:35 I'm just writing the same thing in mzscheme for comparison

7:01 I'm testing a simple particle system, kind of an fireworks effect and currently the mzscheme version seems to be a lot faster than the clojure one and doesn't have much noticiable gc pauses

7:03 any clues on how I could improve the performance? I just have a list of particles [[posx posy] [[velx vely]] that I update and draw

7:19 hoeck: tomppa: can you paste your code?

7:19 tomppa: sure, just a sec

7:20 hoeck: tomppa: there is *warn-on-reflection* and some math primitives

7:22 lisppaste8: tomppa pasted "Fireworks" at http://paste.lisp.org/display/69811

7:23 tomppa: I doesn't have all the code, graphics are handled by awt/java2d

7:23 ... and it isn't meant to look neat. Just a quick test

7:24 Kerris0: just found an online Lisp interpreter http://weblisp.net/

7:25 tomppa: I don't mind if my code is a bit slow but the GC pauses are annoying. mzscheme version is ~identical but doesn't exhibit any gc problems. And is some 3-4 times faster

7:35 if someone wants to try it out here's the jar http://www.yellow-hut.com/blog/wp-content/uploads/fireworks.jar

7:45 okay, when I set -XX:+UseConcMarkSweepGC it works a lot better. Just, umm, what does that flag do

7:47 isn't incremental gc on by default on the client vm?

7:59 it seems that none of my extra and classpath args are used when I run clojure-slime

8:01 Chouser: kib2: the book is good. it's still a bit rough at this point, but the narrative flows very nicely. I think it'll be quite good for anyone who wants to learn Clojure.

8:10 kib2: Chouser: thanks, so I'll wait some time and then buy it. See you, I need to go to work :)

8:11 tWip: I think I'll need to buy them in bulk and sneakily distribute them to my coworkers' desks

8:25 jkantz: Q on maps... how would I map across a map, returning another map?

8:26 do I need to write something to do this or is there some built-in way?

8:26 rhickey: jkantz: (into {} (map (fn [[k v]] ... [newk newv]) amap))

8:27 jkantz: thks

8:28 rhickey: or: (reduce (fn [m [k v]] ... (assoc m newk newv)) {} amap)

8:29 the latter will allow you to conditionally add entries

8:39 Chouser: rhickey: it's nice to have you back.

8:40 rhickey: Chouser: nice to be back!

8:41 gnuvince: good morning

9:22 abrooks: rhickey: How was tabulating? :)

9:25 rhickey: abrooks: it's a lot more than tabulating, but it went well

9:26 abrooks: rhickey: I figured it was more that tabulating. I should have included a wink.

9:29 rhickey: Is the system that you were working on part of the federal election system or something used by a private/commercial entity (or something else entirely)?

9:29 rhickey: http://www.exit-poll.net/

9:30 it's the exit poll that feeds every networks and newspaper - essentially everything you see about voter opinion on election day

9:30 abrooks: rhickey: Ah, cool. I was going to ask if there was any public information about it. Thanks.

9:39 Lau_of_DK: rhickey, how do you feel Clojure stacks against something like ATS?

9:43 rhickey: Lau_of_DK: do you mean this: http://www.cs.bu.edu/~hwxi/ATS/ATS.html

9:49 Lau_of_DK: yes, although I read about it at www.ats-lang.org

9:49 @ rhickey

9:51 gnuvince: Lau_of_DK: what do you mean by "stacks against"?

9:53 rhickey: Lau_of_DK: never heard of it

9:53 Lau_of_DK: Im thinking pros/cons. ATS looks very (http://shootout.alioth.debian.org/u64q/benchmark.php?test=all&lang=all) powerful, and like it has some of the same features as Clojure, as in persistant lists

9:56 gnuvince: all the ATS programs I've seen on that benchmark are 10x as long as all the other programs.

9:59 Chouser: seems like a very different language -- staticly typed, compiled, explicit pointer arithmetic, almost certainly no macros.

10:02 gnuvince: Definitely no leveraging existing Java code ;)

10:05 Lau_of_DK: Alright, thanks :)

10:15 rhickey: accepting proposals for sorted version of set and map literals

10:16 Chouser: you want something syntaxy, not just #=(sorted-map 1 2,3 4,5 6)

10:16 ?

10:17 it could be implicit -- if the keys are printed in order, read them into an sorted collection. I'm sure that would never cause nasty surprises.

10:18 #>{:a 1, :b 2} ##>{:x :y :z}

10:38 rincewind: the to-do-list mentions: arbitrary symbols in | |

10:40 there are currently no pipe symbols in the .clj files in trunk i think

10:54 rhickey: Chouser: yes, not #=(sorted...

10:55 rincewind: yes, thinking forward to |whatever including spaces| as a symbol

10:56 rincewind: when AOT compilation is available, will LispReader.java be ported to clojure?

10:56 rhickey: rincewind: could be, not a top priority though

10:57 I guess a long-term goal might be a bootstrapped version of Clojure

10:58 but bootstrapping has its own set of complexities, few of which contribute to productivity

10:59 Chouser: #>{:a 1, :b 2} #>#{:x :y :z} ?

11:00 Chouser: these are starting to feel a bit like perl, or maybe regex.

11:01 rhickey: yeah

11:01 Chouser: > is nice, but 3 symbols preceding the { is not so much.

11:01 #> feels ok

11:02 ##{:x :y :z} ? less consistent, but fewer chars too

11:02 rhickey: I'm not sure sorted literals are that important, and given the new reader extensibility, at least #=(sorted...) will work

11:03 for print/read

11:03 Chouser: actually it doesn't, but I don't understand the new reader enough to know why

11:03 (class #=(sorted-map :a 1, :b 2)) -> #=clojure.lang.PersistentHashMap

11:03 rhickey: I do, it's due to compiler interpretation of maps - always yields hash-maps right now

11:03 Chouser: oh, ok.

11:03 rhickey: maps in code are evaluated

11:06 these things are all connected, for instance, should sorted-maps in code be evaluated too, especially if there isn't literal syntax for them

11:09 Chouser: ah, subtle. #=(sorted-map (keyword "a") 1) vs. {(keyword "a") 1}

11:10 #= is an odd beast that I definitely do not have a feel for yet.

11:10 rhickey: Chouser: It's not intended for use by humans

11:10 Chouser: heh

11:12 rhickey: for instance above, there's no reason for #=

11:13 Chouser: I guess if there was a general warning -- don't use #= literals in your hand-written code -- it wouldn't be too bad for #=(sorted-map ... to skip eval its arguments

11:13 yeah

11:13 skip eval'ing

11:14 rhickey: In CL, vector literals are constants, if you want evaluation you need to backquote

11:14 In Clojure, I decided to make vector and map literals be evaluated

11:15 this has been very convenient, returning [a b] etc

11:19 Chouser: yes, I agree. It also feels more like python and javascript, which I imagine has eased many people's transitions.

11:19 danlarkin: Chouser: I can vouch for that

11:19 rhickey: but it's a basic fact that there can't be syntax for everything

11:20 (sorted-map ...) works fine when you need it

11:21 the few times I've wanted a map other than hash-map for syntax has been when I've wanted array-map for order preservation

11:21 Chouser: yep. And it's nice that #= can help hold back the need for ever more syntax.

11:22 rhickey: the idea behind #=(what you would write anyway) is that you'll never be inclined to write #= yourself

11:24 it's strictly for read/print representation

11:25 Chouser: so fixing up the compiler such that #=(sorted-map ...) works should be sufficient.

11:25 rhickey: for some definition of works

11:25 I'm leaning towards unevaluated, as-read

11:26 constant

11:26 Chouser: yeah

11:30 rhickey: the other side I'm currently mulling over is whether this print-type-preserving shouldn't be separate from print-readably

11:31 Chouser: so 3 modes of printing (not including "pretty")?

11:31 rhickey: at the repl, I'd like all my maps and sets to look the same

11:32 but when serializing constants, I need to distinguish precisely

11:34 Chouser: would there be any difference for any type other than sorted mapand sorted set?

11:34 rhickey: sure, array-maps vs hash-maps

11:35 maybe different sorted sets with different implementations/perf characteristics

11:35 Chouser: ah, array-maps.

11:35 hm.

11:35 rhickey: generally, there will be N implementations

11:35 I think the repl should be about the abstractions

11:36 that sort of forces to type-annotated serialized versions

11:37 Chouser: but that means this new format really will be just for serialization. Any reason not to hook into Java's serialization at that point?

11:37 rhickey: #=(java.util.HashMap. {:b 2, :a 1}), #=(clojure.lang.PersistentArrayMap. {:b 2, :a 1})

11:38 Chouser: it's binary, tied to class versions etc

11:39 Chouser: ...or at least make the new format compatible with dropping in Java-serialized versions of Java objects that don't have a clojure-print method.

11:39 oh, I didn't realize it was binary. bleh.

11:39 rhickey: there is JAvaBeans serialization which is text and extensible, if somewhat verbose

11:39 very verbose

11:39 Chouser: that's xml?

11:39 rhickey: too verbose

11:39 yeah

11:40 Chouser: could that be used when there's no print-method though?

11:48 rhickey: Chouser: it could, but there's no registry for persistence delegates AFAIK, and the default uses bean properties, not likely to be useful in many cases

11:51 Kawa had an efficient way to store constants using Externalizable, but not many built-in classes implement that

11:57 Chouser: you could base64 the binary serialization. #=(deserialize java.Whatever "...")

11:58 anyway, that's secondary I guess to the core idea of 3 print types

12:02 would *print-meta* still be optional for the serialize form?

12:02 rhickey: no, that's one of the current todos

12:03 this one is that: http://groups.google.com/group/clojure/msg/c77604094dba3b6c

12:03 metadata not serialized

12:06 Chouser: huh. I couldn't make any sense of that.

12:07 so this might make sense as modes on a linear scale from "undecorated" through "serialization": print, print-readably, readably with meta, and serialize

12:07 rhickey: basically the value at the repl gets wrapped in a little fn, which when compiled, serializes the symbol constant, losing its metadata at present

12:08 Chouser: yes, that's one way to look at it

12:09 Chouser: auto-indentation would still have to be a separate flag

12:28 rsynnott: has anyone read this new book?

12:33 Chouser: rsynnott: I've read the half that's available.

12:33 rsynnott: I'm vaguely considering buying the PDF

12:34 though I'm not sure whether I actually need it; the website was quite useful

12:56 gnuvince: Chouser: how is it?

12:57 duck1123: does anyone know if you buy the PDF first if you can still get the discount on the print version, or do you have to buy them together

13:21 danlarkin: any better way to make a string of n spaces? (apply str (map (fn [x] \space) (range 4))) n being 4 for this example

13:24 Chouser: danlarkin: (apply str (replicate 4 " "))

13:25 danlarkin: Chouser: perfect, thanks

13:26 Chouser: gnuvince: It's easy to read. I think it's the kind of ground-up tutorial a lot of people have been asking for.

13:31 gnuvince: Chouser: cool

13:31 Chouser: we'll see when it's complete if it's also going to be a good reference.

13:51 drewr: lol. http://twitter.com/dysinger/statuses/993446623

13:52 rhickey: drewr: I think he was just interested in distributed concurrency, which Clojure doesn't provide yet

13:58 made AFn's Comparator.compare work with predicates too, true values sorting first (sort > [1 2 3 4]) no longer needs comparator

14:10 AWizzArd: What are AFn's?

14:10 danlarkin: Abstract Functions, I assume

14:10 but I know what happens when one assumes

14:11 so perhaps I should have kept my mouth shut

14:12 AWizzArd: regardless if it stands for Abstract Functions or not: what are Abstract Functions?

14:14 wwmorgan: AFn is the abstract class that all functions inherit from

14:14 cemerick: rhickey: many thanks for that change to sort. *very* handy

14:21 Chouser: yeah, pretty.

15:04 drewr: Any particular reason why finally can't return a value in case a catch clause was invoked?

15:05 Chouser: you get the specific catch-clause return value instead, right?

15:06 drewr: No, I get a boolean.

15:08 Chouser: this returns "c1": (try (throw (Exception.)) (catch Exception e "c1") (finally "f"))

15:12 drewr: The boolean was coming from the return value of what I thought was causing the exception. I guess it wasn't, though my catch clause was getting invoked.

15:14 fanda: hello all!

15:14 can I have a question about macros?

15:14 Chouser: danlarkin: go for it

15:14 sorry

15:14 fanda: go for it :-)

15:14 danlarkin: Chouser: :-o

15:14 fanda: i would like to create a macro 'mac

15:14 (mac (run-mac 1 2) (do-not-run-fn 1 2))

15:15 when called like this, if expands run-mac macro

15:15 but it does not expand/run do-not-run-fn

15:15 a returns a list with results

15:16 (list expanded-expression-from-run-mac (do-not-run-fn 1 2))

15:16 run-mac is a constant name - not any macro

15:17 Chouser: you want the raw symbol list '(do-not-run-fn 1 2) in your result list?

15:17 fanda: yes

15:18 Chouser: (defmacro mac [a b] `(list ~a '~b))

15:18 rhickey: drewr: finally is for cleanup side-effects, it runs even when the (returning) body succeeds, so can't define return

15:19 fanda: thanks Chouser, let me try it, if that is what I need

15:28 drewr: rhickey: AH, good point.

15:30 fanda: Chouser: still not there, I give you the concrete example of what I am trying to do

15:30 (defmacro equal-pairs [& expr] (map #(cons '= %) (partition 2 expr)))

15:30 user=> (macroexpand '(equal-pairs 1 1 2 2 1 4))

15:30 ((= 1 1) (= 2 2) (= 1 4))

15:32 now I want to create a macro: (check (equal-pairs 1 1 2 2 1 4) (= 5 5) (= (+ 1 2) 3))

15:32 which returns for the start this: '((= 1 1) (= 2 2) (= 1 4) (= 5 5) (= (+ 1 2) 3))

15:33 it calls the macro equal-pairs and joins its result with all other expressions - unless it is equal-pairs again, which gets called and joined...

15:34 more advanced version of macro 'check returns a list of (expression result) '(((= 1 1) true) ((= 2 2) true) ((= 1 4) false) ...)

15:34 Chouser: you want "check" to be explicitly aware of the "equal-pairs" and treat it differently from "="?

15:34 fanda: yes, exactly

15:35 Chouser: first of all, I think think there's any need for equal-pairs to be a macro

15:36 bah. I mean I equal-pairs can be a fn

15:37 fanda: no, I need to keep both - non-evaluated parameters and evaluated ones

15:37 user=> (macroexpand '(equal-pairs (+) 0 (+ 1) 1 (+ 1 2) 3))

15:37 ((= (+) 0) (= (+ 1) 1) (= (+ 1 2) 3))

15:39 otherwise, I would have to quote everything - '(+) '(+ 1) ...

15:41 rhickey: fanda: do you need equal-pairs on its own? can it just be syntax of check?

15:41 Chouser: (defmacro check [& s] (cons `list (map #(if (= (first %) 'equal-pairs) % `(quote ~%)) s)))

15:41 but you should listen to rhickey :-)

15:42 oh, that's not right. sorry.

15:43 rhickey: Chouser: he shouldn't listen to me?

15:43 :)

15:43 AWizzArd: I think he meant the macro

15:44 fanda: just a second guys...

15:46 Chouser: rhickey: that's right, you got a problem with that?

15:51 (defmacro check [& s] `'(~@(mapcat #(if (= (first %) :equal-pairs) (for [p (partition 2 (rest %))] (cons '= p)) [%]) s)))

15:51 wwwwwuser=> (check (:equal-pairs 1 1 2 2 1 4) (= 5 5) (= (+ 1 2) 3))

15:51 ((= 1 1) (= 2 2) (= 1 4) (= 5 5) (= (+ 1 2) 3))

15:53 or for your original syntax: (defmacro check [& s] `'(~@(mapcat #(if (= (first %) 'equal-pairs) (macroexpand %) [%]) s)))

15:54 but that's kinda weird because the equal-pairs macro doesn't really work on its own.

15:54 fanda: yes, it doesn't have to work on its own...

16:12 jgracin: rhickey: rich, could you please verify memfn definition. it seems to me that ~@args should not go into the arglist of lambda form.

16:19 fanda: thanks guys for help!

16:19 having phone calls and stuff to do...

16:19 greatly appreciate your help!

16:42 rhickey: jgracin: methods aren't variadic - the args to memfn are names used to make a specific-arity call

16:46 jgracin: rhickey: Should this work: (filter (memfn endsWith ".clj") ["a.clj" "b.java"]) ?

16:46 it doesn't seem to.

16:46 rhickey: jgracin: no, it's not partial binding

16:53 jgracin: ok, got it. thanks.

16:54 rhickey: jgracin: I see how the docs could use clarification

16:58 Chouser: jgracin: memfn is hardly ever worth it. #(.endsWith % ".clj")

16:59 jgracin: Chouser: that's what I went back to. (memfn endsWith ".clj") seemed nice, though.

17:00 rhickey: Chouser: right, it predates #()

17:19 Chouser: I've got a bunch of old projecteuler code that uses "thisfn"

17:19 it also uses "true" instead of ":else" in conds

17:26 danlarkin: Chouser: http://blog.danlarkin.org/2008/11/apply-is-lazy-and-i-was-wrong/

17:42 Chouser: danlarkin: :-) thanks

17:53 set and sorted-set are different arities!?

17:54 wwmorgan: Chouser: you're looking for hash-set I think

17:54 Chouser: hm.

17:55 good point.

18:20 blackdog: is it significant that all package names in contrib are lower case? can i use proper case without any problems with AOT in the future?

18:21 rhickey: blackdog: sure, but people choose lower case because upper is annoying, so if you have a choice...

18:21 blackdog: oh ok :)

18:21 rhickey: convention is Java is also all-lower for packages

18:22 in Java

18:32 AWizzArd: Does the jvm support something like "green threads", some very lightweight threads?

18:39 danlarkin: AWizzArd: I don't believe so, but I think if you use a thread pool the effect is somewhat similar

19:00 AWizzArd: rhickey: do you see reader macros for users coming in 2009?

19:06 Chousuke: I haven't seen anyone present a really good argument for user-definable reader macros :/

19:09 AWizzArd: Chousuke: to not depend on what Rich thinks is the best syntax for all tasks and all upcoming problems/datastructures etc. If this is a good argument depends on your opinion.

19:10 Chousuke: Well, you can define syntax with regular macros; though I can see the usefulness of reader macros if you *really* need something a lot.

19:11 AWizzArd: Chousuke: and reader macros just look better for some stuff. Just think about #(foo 1 2 3) vs (# foo 1 2 3)

19:11 This is: reader macro vs macro

19:12 Chousuke: well, yeah, but that's quite a small difference.

19:12 the problem that reader macros are prone to name clashes should be somehow solved first.

19:13 AWizzArd: I don't agree. This difference is so huge that Rich luckily decided to implement it as a reader macro.

19:13 Chousuke: Well, in this case yes.

19:14 as anonymous functions are quite common.

19:14 AWizzArd: Yes

19:14 But currently I can't implement fully featured currying support, which would even more commonly used in Clojure

19:15 Chousuke: fully featured?

19:15 AWizzArd: yes

19:15 Clojure has no currying support, but instead #(..) which comes already close

19:15 Chousuke: clojure has partial though

19:16 AWizzArd: Yes, but this makes not much sense in my opinion

19:16 Currying is syntactic sugar

19:16 it's about brevity

19:16 Currying makes imo only sense when implemented as a reader macro

19:16 gnuvince1: As I said before, I prefer that #(...) anonymous functions be used instead of currying in general, because currying + function composition lead to some really hard to understand code in haskell IMO.

19:16 AWizzArd: (map $(* 3) mylist)

19:16 gnuvince1: It's almost backwards Factor code.

19:17 Where you need to remember what a function takes and what it returns

19:17 AWizzArd: gnuvince1: in fact currying makes code *easier*. That's why Rich implemented something like #(..) in the first place, which already comes close.

19:17 gnuvince1: AWizzArd: the difference is that with #(...) you must be explicit about arguments

19:18 AWizzArd: and I am not talking about implicit currying, but explicit one

19:18 gnuvince1: (map #(* 3 %) my-list) reads bery easily.

19:18 *very

19:18 Chousuke: AWizzArd: that's not much of an improvement over (map #(* 3 %) sequence)

19:19 AWizzArd: and (map !(* 3) my-list) reads even better, and (map !(rgb _ 255) colors) is also better than (map #(rgb %1 255 %&) colors

19:20 gnuvince1: How does the first example read better?

19:20 AWizzArd: because it says: multiply with 3

19:20 gnuvince1: So do ours.

19:21 AWizzArd: how does #(* 3 %) read better than (fn [x] (* 3 x))

19:21 Chousuke: If you ask me !(rgb _ 255) looks really confusing

19:21 AWizzArd: I can read both perfectly and understand them very well

19:21 how can look #(rgb _ 255 %&) *non-confusing* to someone new to Clojure?

19:21 Chousuke: AWizzArd: #() doesn't have a superfluous name ("x") in the code

19:22 AWizzArd: Chousuke: but it has a superflous % in the code

19:22 Chousuke: it's not superfluous

19:22 it's the placeholder

19:22 AWizzArd: the x in fn also not

19:22 Chousuke: it's not a name, it's just %

19:22 AWizzArd: x is not a name, it is just a placeholder too

19:23 Chousuke: but x is a name.

19:23 AWizzArd: both are either names or placeholders

19:23 Chousuke: % is part of the syntax of #()

19:23 AWizzArd: right

19:23 but it is superflous

19:23 gnuvince_: But it *does* help with shouwing explicitly what parameters a function takes

19:23 AWizzArd: (* 3) is a problem, I agree, as this would be implicit currying

19:24 gnuvince_: and !(* 3) is a nice example

19:24 let's do something different

19:24 subtract 3

19:24 (map #(- % 3) coll)

19:24 AWizzArd: gnuvince_: how does #(* 3 %&) show explicitly what parameters * takes?

19:24 Chousuke: AWizzArd: again, once one knows the syntax for #(), it's clear

19:24 AWizzArd: (map !(- _ 3) coll)

19:25 Chousuke: same with the syntax for !(...)

19:25 gnuvince_: AWizzArd: how is that better than the syntactic sugar for fns?

19:25 Chousuke: AWizzArd: but what about (map !(- 3) coll)

19:25 AWizzArd: or whatever the symbol might be

19:25 Chousuke: AWizzArd: shouldn't that be possible too, since !(* 3) is?

19:25 gnuvince_: Chousuke: with subtraction, order matters

19:25 Chousuke: gnuvince_: yeah, I know, and that's the problem

19:25 gnuvince_: 3 * 4 == 4 * 3; 3 - 4 != 4 - 3

19:25 AWizzArd: Chousuke: !(- 3) ==> #(- 3 %&)

19:26 gnuvince_: Anyway, I think we're talking in circles here

19:26 Chousuke: AWizzArd: the latter is better in this case.

19:26 gnuvince_: Since it *should* be a library, it wouldn't matter much to me

19:26 AWizzArd: the better is !(...)

19:26 gnuvince_: I would never use it, but if AWizzArd wants to, his choice.

19:26 That's the beauty of having extensible languages

19:26 AWizzArd: chances are you would use it all the time

19:26 gnuvince_: libraries can "modify" the language

19:27 Chousuke: ! is not a very good macro character for your currying though.

19:27 AWizzArd: Chousuke: I don't care for the character.. see it as a placeholder for the real thing, whatever that might be

19:27 it could be a ! or $ or & or % or ~ or | or whatever

19:28 Chousuke: but I don't see how !(- 3) or !(rgb _ 255) are better than the explicit alternatives, really.

19:28 all they do is hide things.

19:28 that should be visible.

19:28 AWizzArd: but that is the only reason why currying exists

19:28 it is pure syntactic sugar

19:28 and if it should be visible one can use (fn [x] ...)

19:28 Chousuke: but #() provides us with enough syntactic sugar already

19:29 (fn [x] ...) is too verbose; the benefit gained from #() is greater than the benefit of !() compared to the already existing #()

19:29 AWizzArd: #(foo %1 %2 %3 "hallo" %4 -100 %&) vs ~(foo _ _ _ "hallo" _ -100)

19:29 Chousuke: yeah

19:29 I'd take the former.

19:29 rhickey: Clojure doesn't allow user-defined reader macros because they can't be combined - there's no namespace support, unlike for regular macros

19:30 but the case for more currying support is very weak

19:30 Chousuke: the latter does look really nice but it doesn't allow easy changing of parameter order for example

19:31 AWizzArd: Chousuke: yes, the benefit is greater from (fn [..] ..) to #(...), but it also misses some features

19:31 rhickey: so you'll probably have to come to grips with that's how Clojure works

19:31 AWizzArd: Chousuke: you could also say ~(* %1 %1)

19:32 Chousuke: and would that take an automatic "rest" parameter or not? it's pretty confusing :/

19:32 AWizzArd: rhickey: so probably there won't be reader macros any time?

19:33 Chousuke: it is not confusing at all if you would read (in the case currying was present) the then existing manual for 5 minutes

19:33 Chousuke: yeah but it looks like a #(* %1 %1)

19:34 rhickey: AWizzArd: not in the plans as of yet

19:34 Chousuke: which is different.

19:34 AWizzArd: Chousuke: yes, that's right

19:34 Chousuke: and in this case #(* %1 %1) is probably even more efficient as no apply would be needed, as it would be the case for a curried object

19:34 (under the hood I mean)

19:35 rhickey: the clash problem is significant - I don't want libraries that can't be combined. Macros work, user-defined reader macros don't

19:36 AWizzArd: Maybe one could enforce user-defined reader macros need some explicit "turning on" and "turning off"?

19:36 (activate-infix-math)

19:36 Chouser: What about namespaced reader macros, like (chouser/regex .*$)

19:37 AWizzArd: and then you can say: (print ~[4x?-14]) or something like that

19:37 Chouser: lots of people who want reader macros might not be satisfied with that, but it would certainly grant some power.

19:37 rhickey: Chouser: how does that work?

19:38 duck1123: as much as I would like reader macros for my own use, I would hate to see them used by other people and figure out what it means

19:38 rhickey: AWizzArd: CL has user reader macros and the consensus is to avoid them

19:38 duck1123: exactly

19:38 AWizzArd: sure, abosolutely, in 99% of all cases

19:38 duck1123: it's bad enough with the few that we have now (for a new user)

19:39 Chouser: at read-time the macro name would be resolved, recognized as a reader macro, and called with the input stream. It would return the s-expression, with the stream advanced to the end of the expression.

19:39 gnuvince_: Is there demand for an infix arithmetic library?

19:39 AWizzArd: gnuvince_: yes

19:39 Chousuke: maybe have some dispatch-character for user-defined reader macros, and for any defined macros, unless explicitly imported, would have to be qualified with the namespace?

19:40 rhickey: Chouser: the issue isn;t how to implement user macros, but what happens when you have two libraries that define $ ?

19:40 AWizzArd: rhickey: so let's enforce to activate and deactivate them

19:40 rhickey: gnuvince: no

19:40 Chousuke: that might result in some mismatching conventions though, so you could have pieces of code that look similar but do some very different things

19:40 rhickey: AWizzArd: you are unlikely to convince me they are a good idea

19:41 AWizzArd: (Well, if only one person asks for infix arithmetic from this moment on there is demand.)

19:41 Chouser: rhickey: the reader macro in my example is a function named regex in the chouser namespace. Existing namespace resolution and collision rules would apply.

19:41 rhickey: Chouser: so how do you use it?

19:42 AWizzArd: rhickey: I don't want to convince anyone that reader macros are a good idea in general. But I think that you can't forsee everything, and people might come into situations where 1 or 2 reader macros are really helpful

19:42 Chouser: it looks like a function or macro call, but it's actually a reader-macro call.

19:42 rhickey: Chouser: I don't see the point then

19:42 doesn't allow for syntax that regular macros don't

19:43 Chouser: it would allow you to have non-valid-symbol stuff inside the parens. like literal regex chars, or SQL code or something.

19:44 LispReader, upon seeing a symbol at the head of a list, would attempt to resolve it. If it resolves to a reader macro, it would pass the input stream to it, and accept back the s-expression to use in it's place.

19:44 rhickey: Chouser: ah, sort of an escape area

19:44 Chouser: yes

19:45 rhickey: I don't like it :)

19:45 Chouser: heh. ok.

19:45 biab.

19:47 rhickey: AWizzArd: I'd rather there be a consensus of need for something and add it in a way that everyone can use

19:47 AWizzArd: yes

19:49 of course, every decision comes with its own advantages and disadvantages

19:51 rhickey: AWizzArd: yes, I recognize fully this is less flexible than CL in this area, OTOH, I'd like to think Clojure will engender less desert-island programming than did CL

19:52 speaking a common language fosters library development, shared idioms etc. When everyone creates their own language there's less of that

19:53 AWizzArd: And I agree and think this is a good thing. Ironically reducing the amount of flexibility a little bit can have positive effects here.

19:53 rhickey: and even standard reader macros pose an understanding challenge for newcomers

19:54 Chouser: esp. weird ones like #+ and #-

19:54 :-)

19:55 AWizzArd: Well, I just think it is not overly important to be too nice to newcomers. Being a newcomer is a phase in which people are only a short time. Most of your life you have been an expert in programming.

19:55 rhickey: Chouser: coming soon :)

19:56 AWizzArd: concentrating on things that medicore to experts users like/want/need can be a good thing

19:56 Instead of beeing nice to newcomers from the language side we need to write tons of examples and tutorials.

19:57 * rhickey doesn't like print-serializably

19:57 AWizzArd: I will see if I can do that for some german newcomers

19:57 rhickey: print-replica, print-clone(r) ???

19:58 Chouser: (set! *print-detail* :serialize)

19:58 rhickey: Chouser: talking about multimethod name

19:58 Chouser: serialize?

19:59 rhickey: serialize is out, not a good name at all IMO, I think driven by flattening graph notion, but weak

19:59 Chouser: the opposize of "read" is often "write"

19:59 opposite

19:59 AWizzArd: (print-readable ...) maybe

19:59 readably

20:00 Chouser: AWizzArd: that would mean something different

20:00 rhickey: unfortunately you can print to something readable that doesn't read as an identical copy, as happens now

20:00 AWizzArd: ic

20:00 rhickey: this is a stronger notion

20:00 Chouser: unless we change what is now *print-readably* to be named print-for-repl or something.

20:01 rhickey: it's really print-replicator, but that's a mouthful

20:01 Chouser: print-clone's not bad.

20:01 rhickey: clone is so sci-fi though

20:02 Chouser: what get's printed is not the original, so there's not much need for the "-r"

20:02 rhickey: but short, and people get clone

20:02 AWizzArd: reduplicate

20:02 Chouser: ooh, print-dup

20:02 rhickey: Chouser: but it creates the clone when read back, the printed version is not itself a clone

20:03 AWizzArd: (print-twin ...) :-)

20:03 rhickey: nice - leave out enough letters and you can interpret it in many ways

20:04 print-dup(licator)

20:05 AWizzArd: print-genes

20:06 rhickey: print-dup wins - thanks Chouser !

20:07 Chouser: just riffing on AWizzArd :-)

20:11 AWizzArd: without trying this in the repl, what result do you expect? ((symbol "+") 4 10) ==> ?

20:11 duck1123: error

20:11 Chouser: can't cast Symbol to IFn

20:12 rhickey: Symbol's are IFns, like keywords

20:12 AWizzArd: I thought: either error or 14.

20:12 rhickey: 10

20:12 AWizzArd: yes :-)

20:12 but why?

20:12 * rhickey didn't look

20:12 * AWizzArd believes

20:12 Chouser: rhickey: nobody's impressed. ;-)

20:12 rhickey: look up the symbol + in 4, if not found return 10

20:13 Chouser: 4 not being a collection doesn't bother it?

20:14 hm. (get 4 '+ 10)

20:14 rhickey: Chouser: no, get was generalized a while back

20:14 AWizzArd: from get I would not expect errors

20:15 but (nth 4 '+) instead should be an error

20:15 Chouser: AWizzArd: I bet you didn't get very far though -- this is a not a deep or hidden error, is it?

20:16 AWizzArd: I was just playing in the repl, so, not deep at all ;-)

20:16 ((symbol "+") {'+ 8 :a 13} 100) ==> 8

20:17 rhickey: Symbols were made to do self-lookup like keywords a while back, so they have parity for that use, with slightly different ns defaults

20:18 also symbols used as keys can have metadata

20:18 AWizzArd: How can one get somthing like (symbol-function '+)?

20:18 Chouser: resolve

20:18 AWizzArd: thx

20:19 n8 n8

20:33 Chouser: I often use (apply X (map Y ...)) instead of reduce so that I can use #() for Y without the ugly %1 and %2

20:33 I don't know if that's a defensible reason.

20:34 rhickey: Chouser: probably not

20:35 what's an example?

20:38 Chouser: (apply + (map #(- (int %) 64) word))

20:39 rhickey: vs?

20:40 Chouser: (reduce #(+ %1 (- (int %2) 64)) 0 word)

20:40 (reduce (fn [a b] (+ a (- (int b) 64))) 0 word)

20:40 rhickey: you can say % instead of %1 there

20:40 leaves only one ugly

20:40 Chouser: hm, didn't know that.

20:41 rhickey: but I'd advise you to get friendly with reduce, it's likely to be much faster, and more reduce-based idioms are on the way, including some that solve the lazy io problem

20:42 Chouser: hm...

20:43 rhickey: http://okmij.org/ftp/Haskell/Iteratee/DEFUN08-talk-notes.pdf

20:45 Chouser: 91 slides?

20:45 gnuvince_: Chouser: that's Oleg for you

20:46 91 slides of stuff that's gonna blow your brains out completely and make you wonder if you really know anything about programmming

20:47 rhickey: r you could just wait for the Clojure version, after AOT

20:48 the idea is good, and I've got it mostly worked out for Clojure, in my head

20:50 basically IO becomes an enhanced reduce, where the reducing fn can communicate that its done with the reducee, the reducee can clean up, also reducing fn gets passed a source of data rather than one item

20:50 so can read multiple items per step

20:51 based around a new abstraction, an io, like a generating function, new value every time called

20:51 but threadsafe, unlike iterators

20:52 still working on EOS/EIO protocol

20:53 so you'll be able to reduce files/sockets/queues, blocking or non, resources always cleaned up

20:53 drewc: very cool!

20:54 danlarkin: rhickey: you're too smart for me :-o

20:54 rhickey: the Haskell guys came up with the core idea, Clojure won't be exactly the same of course

20:55 they have the same resource management problems with lazy IO as we've seen

20:56 Clojure version should be about 3 slides

20:56 :)

20:56 abrooks: Heh. Naturally.

20:56 drewc: "Lazy IO in serious, server-side programming is unprofessional" he says :)

20:57 danlarkin: destructuring works with strings too, hoorah!

20:57 rhickey: an overstatement of course, you could do lazy io within a with-open and be fine, but handing off the lazy seq is the problem

20:59 abrooks: rhickey: Have you given any thought to a limited eager seq wrapper? Something to gobble, say, N at a time?

21:00 That would be more like buffering.

21:00 rhickey: abrooks: partition?

21:00 abrooks: Sure but partition alters the structure of the seq, right?

21:01 I'm talking about something like a lazy-cat with a delay in the fn slot which will yield N more items at once when the delay is hit.

21:01 Chouser: abrooks: there's also seque

21:02 abrooks: Oh.. wait.. brain cells clicking... deja vu..

21:03 seque is very, very close to what I was thinking of. Probably because I'VE BEEN HERE BEFORE... :-}

21:05 danlarkin: OT but deja vu totally freaks me out

21:07 abrooks: I just chalk it up to by brain failing miserably. Nothing freaky about that. Just annoying. :)

21:10 drewc: i once heard deja-vu as simply your write-head getting a little ahead of your read-head, and reading (remembering) what you just wrote.

21:10 deja-vu described as*

21:19 danlarkin: so I guess that (take 2 "abcd") == (\a \b) and (\a \b) != "ab" is just the way it is?

21:19 I know I could apply str to the list, but I'd like to make it more generic and not have built in behavior for strings specifically

21:21 djkthx: are there default paths LOAD-FILE looks in?

21:21 if so, how can i change/add to it?

21:22 gnuvince_: danlarkin: into?

21:24 abrooks: Strings really aren't collections though they're seq-able. There's no (empty "abc") or (into "" \a \b \c)

21:24 It would be nice though.

21:25 gnuvince_: hmmm

21:25 I thought it did

21:25 Sadness :(

21:25 abrooks: Truly. If only there were someone in this channel who could fix it...

21:26 Chouser: most collections are not themselves seqs. (take 2 [1 2 3]) doesn't return a vector

21:27 abrooks: Chouser: I know. But a string is somewhat like a collection and into/empty/etc. would be nice.

21:28 It's easy to break up a string (last "asdf") (rest "asdf") (first "asfd"), etc. Now what do you do with it?

21:28 Chouser: Strings aren't Persistent -- any change requires a complete copy.

21:28 abrooks: Chouser: I know.

21:28 Chouser: that's why conj and assoc shouldn't work.

21:29 abrooks: Chouser: It still would be nice. Otherwise we're just lost in regex land.

21:29 Chouser: into would be inefficient, but (apply str ...) uses a StringBuilder and thus works pretty well.

21:29 abrooks: I forget, are Java strings a reference type?

21:30 Could Clojure build something which looks like a string but is persistent?

21:32 Chouser: I was thinking about something like that for a text editor data structure.

21:33 (defn seek [n s] (= n (last (take-while #(<= % n) s))))

21:34 that returns true in n is in the ordered infinite seq s

21:34 is there a better way?

21:37 this is not better: (defn seek [n [f & r :as s]] (if (< f n) (recur n r) (= f n)))

21:48 mibu: Anyone in here?

21:49 aspect: um yeah

21:49 mibu: Hi.

21:49 I have two small suggestions for features, who do I turn to?

21:51 Chouser: you can air it here or on the google group

21:51 mibu: Ok then. One is multiple pairs on def, similar to setq.

21:52 The other is cleaning up compiler error messages in the repl.

21:52 Thoughts?

21:52 Is there a reason def does not work on pairs?

21:53 Chouser: there are lots of different error messages coming from lots of spots in the code. There's an ongoing effort to improve individual messages as they come up.

21:53 mibu: on multiple pairs?

21:53 Chouser: I don't know setq. Can you give an example of what you want?

21:54 mibu: Re errors, I'm not talking about something fancy. As simple as replacing e.printStackTrace() with if (!(e instanceof Compiler.CompilerException)) e.printStackTrace(); in the main repl loop's catch clause.

21:54 example for multiple pairs is: (def a 1 b 2) to associate a with 1 and b with 2. Looks better on multiple lines.

21:54 Chouser: latest repl only prints the first line of the exception. Is that not what you see?

21:55 mibu: Really? Mine dumps the stack trace. Which version is the latest?

21:55 Chouser: oh, just to avoid (def a 1) (def b 2) ?

21:55 mibu: yeah about the def

21:55 Chouser: latest is always from svn :-)

21:56 mibu: I prefer the latest *stable* release.

21:56 Chouser: there's a link at clojure.org

21:56 mibu: but it's good to know it's in the trunk.

21:56 Is there a release schedule?

21:57 Chouser: ah. latest release is 20080916

21:57 mibu: I've got that release.

21:58 In that release, it still dumps the stack trace, no?

21:58 Chouser: ok. in svn the full exception is kept in *e and by default only the first line is printed.

21:58 yep, that change missed the release by 3 days.

21:59 mibu: Great, it's good to know it'll be in by default in the next release.

21:59 Is there a release schedule?

21:59 Chouser: I don't know of a predicted release date, but I think the next will be called 1.0

22:00 mibu: chouser, do you know if there are plans to expand def to multiple pairs?

22:01 Chouser: nope, not heard that mentioned before.

22:01 abrooks: I thought someone created a "defs" macro at onepoint, perhaps as a lisp paste.

22:02 Chouser: You can make a case for your change on the google group, and see what kind of response you get.

22:02 mibu: It's not a problem making a macro, it'd just be nice to have it built-in.

22:03 Chouser: abrooks: there's declare, but that's not what mibu wants.

22:03 mibu: That kind of small feature is not worth bothering the group about.

22:04 Chouser: it's not going to happen otherwise. You could provide a patch if you want.

22:05 mibu: What you guys use to for dev environment?

22:05 Chouser: there's a pretty wide variety. lots use emacs, a few use netbeans (+ enclojure), I use vim.

22:05 djkthx: emacs

22:05 personally

22:06 after getting used to slime, it's hard to use anything else

22:06 danlarkin: aye, aquamacs

22:06 mibu: I use the emacs with the clojure-mode, is there something better than that around?

22:06 I tried to get slime to work with clojure, but it messed up my config with sbcl.

22:06 djkthx: yeah, i'm wrestling with that right now actually

22:07 mibu: djkthx, I use slime2 and it's a mess. does the cvs version solve some of these problems?

22:08 djkthx: well, i'll let you know in a minute if i get it working :P

22:08 mibu: :-)

22:08 danlarkin: I'm trying to translate this haskell function to clojure but I'm having a brain lapse... satisfy p (x:xs) = [ (xs,x) | p x ]

22:10 I know that between the []'s is a list comprehension, but what is it iterating on?

22:11 or is it not iterating? is it just returning a list of one (or zero) elements?

22:20 mibu: do agents guarantee ordered execution of requests from a single thread?

22:22 Chouser: mibu: I think so.

22:23 "Actions dispatched to an agent from another single agent or thread will occur in the order they were sent, potentially interleaved with actions dispatched to the same agent from other sources."

22:24 mibu: yeah, I just got to that section. premature question.

22:24 Chouser: :-)

22:25 mibu: So, essentially you can use agents instead of producer/consumer queues, in most cases.

22:26 Is there a reason not to?

22:26 Chouser: I think that's fine. You might look at seque.

22:29 mibu: Seque is good only for efficiency issues. From the logic aspect, it's unnecessary, right? Or am I missing something...

22:33 btw chouser, where did you find out about seque? Does it only appear in the API page or is there another section about it?

22:34 Chouser: It's probably only on the api page. I would also recommend reading through boot.clj -- very educational.

22:38 mibu: educational yes, but not informative. If you hadn't told me about it, I wouldn't have found out about it. When I look for something I need, I check the relevant section in the reference, I don't scan every single function.

22:40 boot.clj is kinda hard to read when you're new to clojure. also, much needed comments are very scarce.

22:42 Chouser: not every function fits well in any particular reference page, but I do think we could use some better way to discover functions

22:42 about the best we've got is (find-doc "queue")

22:44 mibu: The hyperspec managed to cram every single function in CL to a category, and it's very helpful when you're checking out a new area you don't know much about.

22:46 Chouser: I could never find functions in CL

22:46 ...for the week or two that I tried.

22:46 mibu: damn, now I think about all the useful functions I haven't discovered yet and possibly written unnecessarily.

22:47 yeah, CL is not very friendly. some say it's policy to exclude mere mortals from programming in it.... ;-)

22:47 Chouser: :-)

22:49 mibu: hey, we can adopt a similar smug policy. want to write in clojure? read the boot.clj. if someone complains about the lack of comments, tell them it's intentional. :-)

22:49 a language can't be a real lisp without the smug attitude of it's followers...

22:50 * duck1123 shouldn't lisp while drunk

22:50 Chouser: yet another way which Clojure is better than lisp. :-)

22:51 duck1123: I've been driving my self nuts trying to figure out why my connection is closed before I get to it

22:51 turns out my parens were in the wrong place

22:55 danlarkin: duck1123: ouch

23:09 djkthx: mibu: i got it all working pretty harmoniously now

23:09 with sbcl/mzscheme/clojure

23:09 if you want me to post my .emacs file

23:09 mibu: what's your .emacs slime section looks like?

23:10 yeah, I'd like that.

23:10 djkthx: yeah, jas

23:11 mibu: http://pastebin.com/m5854a0fa

23:11 if you were having a problem with progn

23:11 which was the error i was getting

23:11 you just have to prevent certain things from being eval'd when you start slime with clojure instead of common lisp

23:11 mibu: which version of slime you use?

23:12 djkthx: cvs

23:12 the git version on github

23:13 mibu: I want to see if there's a way to make it work with slime2. I have some programs running with swank of that version, and it's a bad idea to mix versions of slime and swank.

23:13 djkthx: ah

23:13 hmm

23:18 mibu: djk, what's slime-fancy?

23:18 duck1123: does anyone know how I can 'let' a local variable in a macro to be made available to forms in the '& body' of the macro?

23:18 I keep getting errors whenever I try

23:19 The only way I've managed to do this is to bind on a global variable like in clojure.contrib.sql

23:21 mibu: djk, thanks for the .emacs, but it seems my problem is not as simple as I thought.

23:21 djkthx: that's too bad =\

23:21 mibu: slime-fancy just adds the nice tab completion and other features

23:21 i was having issue including it

23:22 mibu: right now, clojure-mode does the trick for me. if clojure is as good as it seems, maybe I won't need sbcl and slime anymore.

23:25 danlarkin: oh wow what are the chances... someone already wrote a parser combinator library for clojure, hooray!

23:26 Chouser: duck1123: the called of your macro is passing in the local name to be bound?

23:27 duck1123: I'm basically writing a bunch of with-* macros right now

23:27 I want those macros to make a variable available to the body of those macros

23:28 Chouser: (defmacro let99 [a & body] `(let [~a 99] ~@body))

23:28 duck1123: I'd prefer to not have to specify the name of those variables when calling the macro, but I will if I have to

23:29 Chouser: oh, you want to "capture" the name.

23:29 duck1123: yes

23:29 I want 'a to be available to body

23:30 Chouser: (defmacro let-foo [v & body] `(let [~'foo ~v] ~@body))

23:30 naughty

23:30 duck1123: is that not good form?

23:31 drewc: duck1123: in general, variable capture is a no-no.

23:31 Chouser: in clojure, anyway. arc loves it.

23:31 drewc: entire macro systems have been written in an attempt to avoid even the possibility.

23:32 Chouser: drewc: part of that is attempting to avoid un-intentional capture.

23:32 drewc: arc is a no-no as well... wanton variable capture being among the reasons :)

23:32 Chouser: indeed, and i actually capture variables all the time in CL... but only for internal macros.

23:33 Chouser: intentional capture is less bad, but still -- for example, you may shadow a name the user has been using for a while, forcing them to rename their own variables just to use your macro.

23:33 drewc: exactly. If the macro will be used outside a few select places, best not capture a variable the programmer may be using.

23:34 duck1123: ok the, assuming I want to pass in the name of the var I will use, I get the error: Unable to resolve symbol: resource in this context

23:34 drewc: if it's for hack, or will only be used internally in some module of code and doesn't even make sense outside that context, then go ahead and capture IMO.

23:35 Chouser: duck1123: you're using a pattern like let99 above?

23:36 duck1123: yes

23:36 Chouser: (let99 foo (+ 5 foo))

23:37 duck1123: lisppaste8: url

23:37 lisppaste8: To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste.

23:39 duck1123 pasted "Trouble using macros" at http://paste.lisp.org/display/69887

23:39 duck1123: the part I'm working on is the with-resource

23:40 and add-statement

23:40 the code is not very clean yet, I'm still working on it

23:45 hmm... maybe I forgot to evaluate something... I'm getting a different error now that I've restarted the repl

23:55 djkthx: so, is there a way to package clojure code into a jar or anything?

Logging service provided by n01se.net