#clojure log - Oct 06 2008

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

1:23 sawjig: does gensyms protect from all potential evil of macros?

1:23 like shadowing other variables and such?

1:24 also, where can i find the source code for "builtin" macros like when and when-not?

1:25 blackdog: boot.clj for your second question

1:28 sawjig: ty

1:57 is the use of backquoe discouraged in clojure? i see in boot hickey uses (list form) a lot, not graham-style macros

2:29 Lau_of_DK: Morning gents

2:29 Can somebody direct me to the simplest approach to making an executable .jar file with Clojure code in it?

2:59 yangsx: H4ns: can you send manual.pdf to me? I'm unable to download any files from the clojure group :)

3:24 Lau_of_DK: blackdog down, you in ?

3:25 sawjig: is there no string-libraries in clojure?

3:26 if wanting to work with strings, what is the best way?

3:27 and how do i set default indent to 4 chars?

3:28 Lau_of_DK: Cant you use Javas stringmanipulation routines?

3:37 sawjig: how can i do multiple-value-bind?

3:38 Lau_of_DK: can you give an example of what youre trying to accomplish? mvb doesn't ring any bells with me

3:45 sawjig: user=> (def spam #{:egg 12, :ham 4}) #'user/spam user=> spam

3:45 #{4 :egg 12 :ham}

3:45 user=>

3:45 when i do (get spam egg) i get an error

3:46 (get spam :eqq) returns :egg not the value

3:52 noone used Maps?

3:54 Lau_of_DK: user=> (def spam (hash-map :egg 12 :ham 4))

3:54 #'user/spam

3:54 user=> (get spam :egg)

3:54 12

3:54 #{} gives you a HashSET and not a map

4:00 You can check your constructs with (class spam), which would tell you its a persistantHashSet

4:22 sawjig: http://hpaste.org/10933

4:22 Lau_of_DK: Has anybody here got an idea of how to implement a ListSelectionEvent ?

4:23 sawjig: why is splitall not splitting more than once? try (splitall "hellola" \l)

4:26 Lau_of_DK: I think you need to place (recur) within a loop or for statement

4:29 (nevermind about the listener)

4:46 sawjig: http://hpaste.org/10934

4:46 still not working

4:57 i thought clojure supported polymorphism, why not + for cons?

5:00 i am trying to add some stuff in boot.clj, do i ahve to recompile it then? because after i have done so i cant use it in the repl

5:01 or i ahve to add it in some other file too?

5:37 leafw: sawjig: use user.clj

5:53 sawjig: leafw: where is user.clj? cant find it in src and not src/jvm

6:21 leafw: sawjig: you create it. And put it in whatever you want. Place it in the instantiation directory.

6:22 s/it in /in it/

6:22 Lau_of_DK: Can someone here point me to some info that will let me create an executable .jar file with clojure code in it ?

6:31 Can someone here point me to some info that will let me create an executable .jar file with clojure code in it ?

6:33 sawjig: is the instantiation dir /src or just /clojure?. clojure.jar is in /clojure but boot is in /src

6:36 dont i have to point something to this file? or is user.clj looked for by the interpreter automatically?

6:36 ah wow it worked

6:37 i put it in /clojure

6:38 hoeck: sawjig: it must be somewhere in the classpath

6:40 leafw: Lau_of_DK: user jar cf MyThing.jar my_script.clj MyMainClass.java , where the main class launches an interpreter that reads the clojure scripts included in it.

7:32 Lau_of_DK: Im not getting the .jar setup, rhickey, is there a place where I can put my main .clj in clojure.jar to make that file executable so that it fires up my program ?

7:43 sawjig: http://hpaste.org/10941

7:44 how do i do if i want python-like ifs?

7:44 like if his is true do that and have several ina row

7:44 when doesnt help here, i dont want to nest

7:46 rhickey: sawjig: are your tests exclusive, or do you want them all to run?

7:46 sawjig: i want all to run

7:46 rhickey: and if they pass you want a side-effect?

7:48 Lau_of_DK: rhickey, did you catch my question about .jar?

7:48 rhickey: Lau_of_DK: user.clj will be loaded by default

7:49 sawjig: user.clj is very nice, i like how to open and hackable clojure is.

7:49 rhickey: yes i want a sideeffect then

7:49 i mean i could to this, but not in a clean way

7:50 if could nest a hwole bunch of ifs i guess

7:50 but thats not very clean

7:51 rhickey: sawjig: http://groups.google.com/group/clojure/msg/f7a1b33e2886008c

7:55 sawjig: thanks rick

7:57 could you perhaps have a quick look at http://hpaste.org/10943 and tell me why splitAll doesnt work?

7:59 rhickey: what is it supposed to do?

7:59 at first glance I can say if you are using reverse you are probably not leveraging Clojure's data structures

8:02 there's only one call to reverse in boot.clj and it's not to fix up a recursive return value

8:03 also please paste for this channel here:

8:03 lisppaste8: url

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

8:12 qwer pasted "tiest" at http://paste.lisp.org/display/68037

8:12 sawjig: ^^

8:32 lisppaste8: hoeck annotated #68037 with "split" at http://paste.lisp.org/display/68037#1

8:42 Lau_of_DK: rhickey, practically speaking, how do I add my user.clj to the clojure.jar file ?

8:56 isnt there a flat-map or flatten function in clojure ?

8:58 sawjig: isnt (defn f [& x]...) meaning optional params?

8:58 or it is multiple?

8:59 cemerick: Lau_of_DK: try mapcat

8:59 Lau_of_DK: cemerick , thanks

8:59 cemerick: sawjig: there are no optional params, & x indicates rest parameters, and the name that the rest of the parameters are bound to within the fn

9:00 Lau_of_DK: cemerick , mapcat did the exact trick, thanks alot

9:00 cemerick: Lau_of_DK: np

9:36 rhickey: ok - maps are now Maps

9:37 drewr: Awesome!

9:37 That's going to greatly simplify some serialization code I've written.

9:38 rhickey: it was a pretty extensive change, so let me know if you encounter any glitches

9:38 drewr: Will do.

9:41 sawjig: can i raise an error somehow? define my own?

9:41 drewr: sawjig: (throw (Exception. "msg"))

9:41 You can subclass java.lang.Exception too, of course.

9:53 Chouser: clojurescript/avoid-java-in-boot.patch is now updated to work with the latest clojure svn

9:54 rhickey: Chouser: ok - that was fast!

9:54 Chouser: :-) git auto-merges pretty well.

10:06 sawjig: what is the point with conj? isnt it just (conj b a) instead of (cons ab) ?

10:07 can i cons to the end of a list somehow?

10:07 Chouser: conj is polymorphic -- when used on a vector, it adds on the end.

10:07 when used on a list, it's just like cons

10:08 you can also use conj on sets and hashes

10:09 http://clojure.org/data_structures click on "Collections" in the table of contents

10:09 sawjig: ok cool

10:09 hickey said before he only used reverse once in the implementation of clojure. but i find myself needing to reverse a lot when using recursion

10:09 is that bad technique then or is there some way to cons to the end?

10:10 rhickey: sawjig: if you use vectors your data will be in the right order

10:10 Chouser: if you're using lists and reverse a lot, there's a good chance you can use vectors and not need to reverse -- will be faster and less code

10:19 sawjig: well im working on lists and strings and need to return the same type that was passed...

10:21 Chouser: I hardly ever use lists in clojure. are you sure you need to?

10:21 even so, you could build a vector while recursing and convert to a list (or seq) before returning it.

10:42 sawjig: does that create the same performance-penalty?

10:42 as reversing

10:44 lisppaste8: sawjig pasted "reversing" at http://paste.lisp.org/display/68046

10:45 sawjig: some examples ^^ using reverse

10:46 drewr: What's tl?

10:46 cemerick: sawjig: no -- creating a seq from a vector is essentially free, whereas reversing a list is O(n)

10:48 sawjig: tl=tail=first,hd=head=rest

10:48 cemerick: ok thanks ill use that instead then

10:49 drewr: sawjig: Yeah, but what is the symbol "tl" in your code mean?

10:49 Did you redefine rest?

10:50 sawjig: it means rest

10:50 i defined it in user.clj

10:50 because i hate writing long names...

10:50 (defn tl [xs] (rest xs))

10:50 drewr: OK.

10:50 I would use idiomatic Clojure instead though.

10:51 sawjig: yes renamed it, rest is still there. i know some might hate that but i like them to have equal length(liens up nicely) and be short sinc eu use them so much

10:51 H4ns: very hard to get code reviewed which uses a different vocabulary.

10:51 Chouser: I pretty rarely use first or rest, either. Between destructuring and high-order functions, I rarely need to type out "first" and "rest"

10:51 sawjig: yes true

10:52 ok illkeep thta in mind, im a lisp-noob so i prob write some primitive and dumb stuff

10:52 H4ns: sawjig: first off, do not redefine the vocabulary. get an autocompleting editor if you hate typing things too often

10:53 drewr: sawjig: Read boot.clj.

10:53 Chouser: sawjig: no worries -- people around here are generally quite willing to help if you're willing to learn.

10:53 H4ns: sawjig: second: don't try to optimize until you know what you need to optimize

10:53 cemerick: sawjig: it's just a matter of learning the idioms -- not really a question of dumb or primitive

10:55 abrooks_: Hrm. 63 of the files in Subversion have *nix (LF) style EOL, 52 have DOS (CRLF) style EOL. I noticed this while looking at the recent rev 1052 diff which spans a lot of files.

10:56 We should probably set svn:eol-style native on all the source files.

10:57 Chouser: sawjig: drop-last is already in boot.clj -- doesn't it complain when you try to def it?

10:58 anyway, you might want to look it up in boot.clj; it doesn't use reverse

11:03 sawjig: drop-last isnt in boot clj but i have clojure_20080612, has it been added lately? i downloaded some time ago but havent played with it until now

11:04 H4ns, i can add auto-completing in emacs right?

11:05 H4ns: sawjig: yes - M-/ completes something that you typed, considering all currently loaded buffers. that is enough for me, but you can allso set up explicit completion dictionaries. never did that.

11:13 Chouser: sawjig: latest release is 20080916 or you can use svn

11:17 tom`: hi all, I'm trying to get clojure working with slime, but I keep getting NoClassDefFoundError

11:18 drewr: tom`: While doing what?

11:18 tom`: swank-clojure-jar-path is set to the location of clojure.jar

11:18 starting slime (M-x slime)

11:18 H4ns: lisppaste8: url

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

11:18 tom`: I can paste-bin the inferior lisp output if it'llhelp

11:19 drewr: tom`: If you start slime with M-- M-x slime, can you choose clojure as your dialect?

11:19 lisppaste8: H4ns pasted "Clojure related section from my .emacs" at http://paste.lisp.org/display/68049

11:20 sawjig: howdo i turn [(\h \e \l \l) (\o \space \t \h \e \r \e)] back into a string?

11:20 lisppaste8: tom pasted "problem starting slime, *inferior-lisp* output" at http://paste.lisp.org/display/68050

11:20 H4ns: tom`: that, with path strings tweaked to suit, works for me on windows, macos, freebsd

11:20 lisppaste8: drewr pasted "My SLIME config" at http://paste.lisp.org/display/68051

11:20 Chouser: sawjig: (map str thing)

11:20 H4ns: tom`: with swank-clojure from git, cvs slime and svn clojure

11:21 tom`: H4ns: I'm using all those, clojure starts fine when I run it from shell

11:21 I'm on Ubuntu if that makes any difference

11:21 Chouser: sawjig: oh, or maybe (map #(apply str %) thing)

11:22 H4ns: tom`: from looking at the error message, i'd say the path to your clojure.jar is not correct

11:22 tom`: drewr: Yes, it's the only option right now

11:22 H4ns: tom`: i'm using swank-clojure-binary because i have some additional classpath settings to make and want to use the same settings on the shell and with slime.

11:22 tom`: H4ns: I've verified that is correct (and fully expanded using expand-file-name)

11:23 will try swank-clojure-binary

11:24 drewr: tom`: I use a custom version of http://github.com/jochu/clojure-extra/tree/master/sh-script/clojure.

11:25 sawjig: in cl i cn do (reduce '* '(1 2 3)) -> 6, can i do something like that in clojure instead of suing (fn[...)

11:25 tom`: I've just set it to a sh script containing "java -cp clojure.jar clojure.lang.Repl src/clj/clojure/boot.clj" which is the line I use to boot it from the command line

11:25 drewr: sawjig: user> (reduce * [1 2 3])

11:25 6

11:25 sawjig: ok but on a list?

11:25 drewr: user> (reduce * '(1 2 3))

11:25 6

11:26 sawjig: hey wtf i thought i tried that lol

11:26 drewr: Clojure's a lisp-1, so you don't have to quote the function.

11:26 tom`: ok, I set swank-clojure-binary to that script but I still get the exact same error which seems a bit odd. Do I have to do anything specialto make it use swank-clojure-binary

11:27 drewr: tom`: OK, that's fine. Do you change to the clojure directory before that command?

11:27 tom`: drewr: good point, that'll be it won't it. Let me just go fix that

11:28 drewr: cd /path/to/clojure && exec java -cp ...

11:29 H4ns: i'd rather use an absolute path for the jar and let clojure start in whatever directory i'm currently set to in emacs.

11:29 sawjig: drewr: is there scanl (=scanleft = reduce and return all the intermediate values)

11:30 drewr: H4ns: I would too.

11:31 sawjig: Like Haskell's? http://www.zvon.org/other/haskell/Outputprelude/scanl_f.html

11:31 sawjig: yes like haskells

11:32 i wrote it,poste d before, just wondering if it wad there already, scan/dorun does soemthing else

11:32 drewr: I'm no functional prog expert. How is scanl different from map?

11:33 tom`: I switched to using the clojure startup script from the coljure-extra git

11:34 I can now run it using ~/clojure/clojure from any directory and it works fine

11:34 but I still get the same error in slime :(

11:34 drewr: C-h v swank-clojure-binary

11:35 H4ns: tom`: are you sure that your script is executed when you start slime in emacs? did you restart emacs?

11:35 sawjig: (drewr: scanl is reduce and all the intermediate values

11:35 so (scanl + 0 '(1 2 3 4)) -> (1 3 6 10) or (0 1 3 6 10)

11:36 drewr: Ooh, this is cool: http://www.haskell.org/hoogle/?hoogle=scanl.

11:36 tom`: H4ns: will try retstarting emacs now, I was just shutting down slime then reloading

11:36 drewr: We need a Cloogle!!

11:36 tom`: back in sec (accessing irc via emacs)

11:36 sawjig: how do i convert from vector to list?

11:37 drewr: sawjig: (apply list [1 2 3])

11:37 * tom` slaps forehead

11:38 H4ns: tom`: works now?

11:38 tom`: yep, restarting emacs did it

11:38 thanks for the help

11:38 H4ns: tom`: good. i spent the last 10 days wrestling with these kinds of issues, so i can feel the pain :)

11:38 tom`: bloody computers :p

11:39 drewr: Burn the lot of 'em!

11:40 tom`: how have you guys found the slime support in Clojure? I'm looking into it as a possible alternative to CL for a new project and slime is one of the most important factors (it's going to involve lots of exploratory programming)

11:41 H4ns: tom`: it works, but it is not as mature as cl support. i find it not so useful to explore whatever the platform provides, but that may not be an issue for you

11:41 tom`: a real down side is the lack of support for *1, *2, *3

11:42 blackdog: new versions of clojure do havethat

11:42 *1 etc

11:42 H4ns: blackdog: it is slime that does not have it, i think.

11:42 blackdog: ah ok

11:43 tom`: thanks, I'll carry on trying it out

11:44 H4ns: i'm not sure if M-. is supposed to work. i'm not at the point where i would miss it, but soon will be

11:44 tom`: I do like the look of Coljure, my biggest complaint about CL is that it's not enough of a functional style language

11:45 sawjig: how do i convert [ 1 2 3] to (1 2 3) and (\h \e \ l \l \o) to "hello" ?

11:47 blackdog: (apply str `(\h \e))

11:49 drewr: tom`: I think if you don't have much history with CL, then going with Clojure is a no-brainer.

11:50 If I was really productive in CL it would have been a much harder switch for me.

11:50 I'm your typical Lisper that ends up reaching for Python when he needs to get things done, but with Clojure I find I don't have to do that.

11:50 sawjig: how do i backquote on windows?

11:51 alec: tom`: Clojure and SLIME have worked well for me coming from a CL environment. It's not perfect, but it's good enough, and the swank-clojure maintainer is *extremely* responsive and helpful.

11:51 drewr: sawjig: What do you mean? Entering the backquote character?

11:52 sawjig: yes

11:52 `

11:52 ah

11:52 drewr: What's wrong with Windows?

11:52 sawjig: its not linux?

11:53 drewr: (That was a very contextual question. :-))

11:53 sawjig: so how do i convert from vector to list?

11:53 (apply list...) doesnt work since list well lists things

11:53 danlarkin: sawjig: I think drewr means that backquoting on windows is the same as backquoting anywhere else

11:54 sawjig: well i found out how

11:54 drewr: sawjig: I don't know what you mean. (apply list [1 2 3 4]) => (1 2 3 4)

11:54 tom`: are there any good printable docs? All I can see right now is the wiki

11:55 drewr: tom`: There's a PDF in the Google Group.

11:56 tom`: thanks, didn't even know Google Groups had a file section

12:07 When I get an error in the slime repl it doesn't let me go into debug or even tell me which file the error is in, am I doing something wrong?

12:13 drewr: Yeah, since SLIME uses the clojure.lang.Repl, I think it can't figure out where the code occurred.

12:13 s/code/error/

12:16 tom`: doesn't that get really impossible? Not having a debugger is one thing, I can live with that, but not even knowing which file the error is in...

12:16 sawjig: why does rest [1 2 3] return the list (2 3) and no the vector [2 3] ?

12:17 drewr: sawjig: It's not a list. It's a vector that implements ISeq.

12:17 The seq abstraction is the key to much of Clojure.

12:18 tom`: Yes, it can get frustrating. That's one of the biggest shortcomings of Clojure right now.

12:18 sawjig: conj on a vector is O(1) right?

12:18 drewr: tom`: Although, Java people seem to do just fine with their tricks. I don't share their background.

12:21 tom`: that is a bit of a pity, I assume that it's quite hard to get that functionality working otherwise it would have already been done

12:21 that will probably be the clincher though, I think I'd go mad trying to cope with it

12:22 cemerick: while clojure error reporting isn't the greatest, I've never seen a situation where the stack trace doesn't pass through the offending code's file/line number

12:23 sawjig: (conj (rest [1 2 3]) 4) -> (4 2 3)

12:23 tom`: cemerick: I'm not getting a stack trace, is it just because I've got something set up wrong then?

12:24 drewr: tom`: No, that's not normal. I've found that some errors with swank have stopped producing stack traces. I think it's a bug.

12:24 Maybe not with clojure.

12:24 cemerick: tom`: I don't use emacs, but perhaps it's dropping clojure.lang.Repl's stdout/stderr on the floor?

12:24 * drewr steps afk

12:25 sawjig: let [[h t] (split s delim)], is that patternmatching osmehow?

12:25 tom`: ok, that's not so bad then, any idea what I might be able to do to fix it?

12:25 cemerick: sawjig: yes, that's destructuring

12:25 tom`: not a clue, sorry :-) I know there's some emacs users floating around, though.

12:26 tom`: I'll try the mailing list

12:30 sawjig: how can i get the typeof something?

12:30 rhickey: sawjig: (class x)

12:30 sawjig: lets say i have a function that takes a string lsit or vector and i want to return the same type that was passed so drop-last "hello" returns "hell" and not (\h \e \l \l)

12:32 (apply (class "hello") '(\h \e)) results ina ne rror though

12:32 Chouser: sawjig: (\h \e) is probably a seq on a String. If you use the java methods of String, you'll get Strings back instead of seqs

12:33 rhickey: for types other than string, (into (empty x) (map f x))

12:33 Chouser: but if you don't want to do that, you can use (apply str '(\h \e))

12:33 rhickey: for string, you'll have to apply str to the result

12:34 Chouser: (class "hello") returns java.lang.String, which is not callable, so that's why it doesn't work with apply.

12:34 cemerick: rhickey: interface injection would eliminate that divide, yes?

12:35 rhickey: cemerick: maybe

12:36 the problem is strings are not a persistent data structure - they are immutable but not persistent

12:36 apply str uses a StringBuilder internally and is fast and efficient

12:37 but treating strings like IPersistentCollections would have to full copy on write

12:38 cemerick: I've been working on digesting some of the "results" from the JVM summit of late.... :-)

12:39 lisppaste8: sawjig annotated #68046 with "scanl apply class" at http://paste.lisp.org/display/68046#1

12:40 sawjig: ^^ (apply (class x) y) doesnt work though if y is a vector and x is a list

12:41 rhickey: sawjig: classes are not functions

12:42 sawjig: so how could i do what want without cheecking a whole lot of cases?

12:48 lisppaste8: Chouser annotated #68046 with "scanl via reduce?" at http://paste.lisp.org/display/68046#2

12:48 sawjig: and can i define + for strings?

12:51 cool but now it still returns a list

12:52 class clojure.lang.APersistentVector$Seq

12:52 Chouser: it returns a seq on a vector

12:52 right

12:52 how is that bad?

12:52 sawjig: actually but i cant conj to the end of it

12:53 (conk (1 2 3) 4) -> (4 1 2 3) instead of (1 2 3 4)

12:53 conj ^^

12:53 Chouser: right, you'd need a vector to conj on the end. Simplest is to wrap in vec: (vec (scanl ...))

12:54 that's not the fastest, though, since it's building up a vector internally. You'd just have to rewrite it so it doesn't have the extra leading value (which I skipped using "rest")

12:54 sawjig: but why cant i have it return a vectoe if pass a vector?

12:55 Chouser: you can

12:55 sawjig: and i cant do (apply (class x) y) so i have t check if class x = someclass apply someclass y

12:55 Chouser: why do you keep trying to call a class?

12:56 What do you expect it do to? Do you want (into (empty x) y) or something?

13:00 sawjig: if i do (scanl + 0 [1 2 3]) i want [1 3 6] back if i do (scanl + 0 '(1 2 3)) i want (1 3 6)

13:01 ah yes into works

13:02 oh well if i conjs to a list it get sreversed so it doesnt worka y way

13:03 Chouser: of course conjing onto a list reverses it, that's the direction that lists grow. If you didn't want it reversed, wouldn't you use a vector?

13:03 kotarak: Hmmm... What is the Sequential interface for?

13:03 Chouser: conjing onto a set puts things in random order. These are the features of the data strctures you're using.

13:05 sawjig: yes i know, im just thinking about a way to get what i want

13:05 Chouser: kotarak: http://clojure.googlegroups.com/web/chart.png

13:06 kotarak: I think it just indicates if a collection is going to retain its order (like a vector) vs. not (like a set)

13:07 lisppaste8: rhickey annotated #68046 with "lazy scanl" at http://paste.lisp.org/display/68046#3

13:08 kotarak: Chouser: well, yes. I know this chart. But what is Sequential for? It's empty. I would expect seq() there (which is my understanding of "seq"uential). And an ISeq is not Sequential? I suspect a deep misunderstanding of ISeq on my side.... :(

13:10 Chouser: kotarak: well, there are things for which seq work that are not themselves sequential (like sets and maps)

13:10 rhickey: kotarak: it is a marker interface, all implementors indicate they are essentially sequential - i.e. lists, vectors, seqs

13:10 Chouser: But I am surprised ISeq is not Sequential, nor is IndexedSeq

13:11 rhickey: Chouser: they could be, all implementations of them are

13:11 Chouser: oh, IndexedSeq is just an interface, I see.

13:13 kotarak: Ok. A set is not Sequential, but a seq of a set is. When all seqs are Sequential, why is then ISeq not?

13:14 Chouser: kotarak: as rhickey just said, it could be -- all the classes that actually implement ISeq also implement Sequential.

13:14 kotarak: Just asking, because it caught be surprise.

13:14 rhickey: kotarak: that shouldn't matter, since you can only ask a concrete thing if it is sequential and they all are

13:14 so would only be a convenience thing for implementors of ISeq - it has been requested

13:14 Chouser: hm, there are a lot of nested classes missing from that chart.

13:14 kotarak: I implemented a class with ISeq and it blew up with nth.

13:15 rhickey: there you go :)

13:15 I'll fix, just a sec

13:15 kotarak: rhickey: :) geeshh... you are support in its essence. :)

13:17 rhickey: kotarak: it's up - rev 1053

13:17 kotarak: rhickey: cool, thanks. :)

13:17 rhickey: np

13:18 kotarak: Are there any plans to migrate other functions as nth, get, etc. to multimethods like pr?

13:19 rhickey: kotarak: probably not, for perf reasons since they are so primitive

13:19 also I don't want the semantics to spiral out of control

13:20 people have gotten some really bad habits from monkey patching in other languages I think

13:20 kotarak: ok. Would have been nice. (Did a test balloon with nth and it seemed to work fine, but performance should of course not be sacrifised....)

13:21 rhickey: Nice Clojure compliment from Cliff Click: http://groups.google.com/group/clojure/msg/241b23524bd585a1

13:22 Chouser: updated http://clojure.googlegroups.com/web/chart.png

13:27 kotarak: Oh. Btw, may I vote for gen-class to require the namespace, not the file directly?

13:36 scgilardi: regarding the idiom "(into (empty x) (map f x))", it works nicely in a lot of cases. One thing to watch out for is when it's applied to a list, the results are in reverse order from the original.

13:38 Chouser: sure, but if you peek and pop, you'll get things in the same order as you put them in, whether it's a list or vector.

13:38 pjb3: makes sense, assuming it is just conjing each item in the seq into the empty list

13:39 scgilardi: If it were abstracted into a function, perhaps subclases of Sequential could use a vector internally and then either return it or convert it to the input type as appropriate.

13:40 Chouser: but into also works on sets, sorted maps, hash maps ... I think you have to pick if you want polymorphism or not.

13:40 If not, say (into [] ...) and get it in the order you want.

13:41 scgilardi: right, this came up in trying to write a polymorphic version. Whenever order doesn't matter (hash) or enforced by the data structure (sorted) or if it's a vector, the answer is unsurprising.

13:42 rhickey: scgilardi: I think no one should be surprised at things getting added to the front of a list - remember into works with a populated target as well

13:45 so if I poured some more things into a large list I wouldn't expect them to be appended, with all the copying that would entail

13:45 scgilardi: right, I'm not criticizing into, just noting that when I first saw "(into (empty x) (map f x))" returns its result in the same type of container that it was give, I took it to mean that if "f" were "identity", I would get a result "=" to what was passed. That's almost always true, but not for list. Hence the "something to watch out for".

13:46 rhickey: scgilardi: I think it might be interesting to have ctor, like empty, that would return a corresponding contructing fn

13:46 constructing

13:47 (apply (ctor x) (map f x))

13:47 or something

13:47 scgilardi: ah neat, yes that looks like it would work nicely.

13:48 rhickey: ((ctor x) (map f x)) ?

13:49 scgilardi: right, that would be better I think. ctor takes seq and makes a collection from it.

13:49 Lau_of_DK: Evening gents

13:49 scgilardi: Heya, Lau

13:49 rhickey: scgilardi: might make a nice multimethod

13:50 cemerick: FWIW, 'ctor' isn't exactly common verbiage (though I love the idea)

13:50 rhickey: name suggestions welcome

13:50 Chouser: "new"

13:50 scgilardi: hehe

13:51 rhickey: Chouser: but it returns a fn

13:51 Chouser: ah, good point.

13:52 rhickey: the problem with polymorphic new is it has to be reflection based

13:52 cemerick: init?

13:52 Chouser: foo.constructor returns a function that creates a new instance of foo's class. In JavaScript.

13:53 scgilardi: yes, "constructor" does have a strong prcedent for this role

13:54 (ctor is short for constructor in C++ circles)

13:54 rhickey: where I used to hang out, apprently :)

13:54 apparently

13:54 cemerick: scgilardi: yeah, I discovered that not too long ago (not ever having been in the C++ pool)

13:55 scgilardi: rhickey: do you recall who wrote the "javadoc" function that (I think) I saw posted here?

13:55 rhickey: cgrand

13:55 cemerick: Given the necessary presence of the constructor notion in Java, I'd say that using "constructor" would be overloading the term too much.

13:55 scgilardi: cgrand: thanks for that. I think it's great. Please consider making it a contrib.

13:56 "factory" is possible.

13:57 cemerick: yeah, factory is good

13:58 scgilardi: gotta run. thanks

13:58 rhickey: but what if the default _did_ call the constructor (had to force myself to type that out) reflectively

13:59 cemerick: constructor isa factory?

13:59 Chouser: in Javaland, a factory is a static or instance method, completely different from a constructor, right?

14:00 cemerick: Chouser: virtually always static

14:00 A constructor is really just a special method on an instance

14:01 * rhickey still likes ctor

14:01 dudleyf: ctor isn't just a C++ term

14:01 scgilardi: Chouser: right, and we're talking about a function here that given an exemplar, returns a new one of those. Hmmm, it's an empty-clone.

14:02 (ctor x args) could create the object and then call its constructor with the args

14:02 rhickey: scgilardi: not really, empty is that, this is a fn that makes an instance given stuff

14:03 scgilardi: (right

14:03 so it's a lot like "new", but takes an object instead of a class

14:03 drewr: Chouser: Thanks for the class diagram!

14:03 rhickey: I think it could take a class as well

14:03 Chouser: and returns a function instead of an object

14:03 * drewr is about three years behind on list messages

14:04 scgilardi: right, ok.

14:04 Chouser: drewr: :-) sure

14:04 scgilardi: what does javascript call that? they do new by cloning something that exists, don't they?

14:05 dudleyf: scgilardi: I wish

14:05 rhickey: the more primary notion takes a class, as you could build the other from (ctor (class x))

14:06 Chouser: function Foo(){}; foo = new Foo(); foo.constructor == Foo

14:06 scgilardi: but there's a name for this kind of non-class-based object orientation... it escapes me at the moment.

14:06 dudleyf: prototype-based

14:06 Chouser: scgilardi: prototypes, but that's not what this is.

14:06 scgilardi: ok

14:07 thanks for the word. it doesn't have to drive me crazy not knowing it now.

14:08 Chouser: that has to do with inheritence, where instead of pointing to a parent class, your derived class points to a prototype -- an instance of the parent.

14:10 blackdog: "make" ?

14:11 scgilardi: I think if this new thing takes arguments and calls constructors, ctor or factory work. (ctor (class x)) looks a lot like "new (class x) [args]". As a special form, new could be overloaded to do this. any merit?

14:12 Chouser: if it's returning a function, "maker" would be more accurate than "make", while if it's actually calling the constructor perhaps "new" could work.

14:12 ...although my earlier mention of "new" was definitely meant as a joke!

14:12 rhickey: new has to map to actual constructors, and isn't extensible, this is a pseudo ctor - create something from a collection of other things, subject to interpretation as a multimethod

14:13 I don't want people to start doing a lot of reflective construction

14:14 scgilardi: wouldn't the target class still need a constructor that accepts "a collection of other things" (in this case) or "other things" in general?

14:14 in C++ a copy constructor that accepts seq (in this case)

14:14 rhickey: scgilardi: all of the Collection classes already do, but if a multimethod you could do whatever you want

14:15 Chouser: you could insert a 1-second delay to discourage its over-use

14:15 scgilardi: :)

14:15 rhickey: reflection already does that, no?

14:15 Chouser: reflection + multimethod gets you close

14:16 rhickey: the point of using a multimethod is you could make it fast

14:16 predefine for all collections and you might not need any others

14:16 * scgilardi leaves this in very capable hands

14:16 rhickey: string version could use a StringBuilder internally

15:11 lisppaste8: gnuvince pasted "Slow string accumulation" at http://paste.lisp.org/display/68062

15:13 rhickey: gnuvince: see slurp in boot.clj

15:18 gnuvince: rhickey: (let [u (new URL "http://www.yahoo.com")] (slurp (. u openStream)))?

15:20 No, that doesn't work.

15:21 Chouser: gnuvince: I think he meant you can look at how it builds a string faster.

15:21 rhickey: gnuvince: I meant look at the source for slurp, slurp doesn't read from urls

15:21 gnuvince: OK.

15:25 Chouser: gnuvince: (apply str (line-seq (ds/reader (.openStream (URL. "http://www.yahoo.com")))))

15:26 I got the ds namespace like this: (ns user (:require [clojure.contrib.duck-streams :as ds]))

15:27 oh, you can actually drop the .openStream bit -- ds/reader will do that for you

15:30 gnuvince: I must be doing something wrong somewhere, because it takes 8 seconds to fetch 3 comics while my original Python program fetches 20 in 3 seconds

15:31 Chouser: huh, you can leave out the URL ctor as well: (apply str (line-seq (ds/reader "http://www.google.com")))

15:32 rhickey: don't you want a with-open in there?

15:32 Chouser: oh, I suppose I do.

15:33 (with-open r (ds/reader "http://www.google.com") (apply str (line-seq r)))

15:34 gnuvince: your python wasn't going in parallel or anything, right? :-)

15:34 gnuvince: Chouser: it was.

15:34 Chouser: oh, and your clojure is too?

15:34 gnuvince: Chouser: I'm trying to at least.

15:34 Can't say I'm succeeding

15:36 Chouser: gnuvince: you could stick some println's in, like before and after each page is fetched -- ought to be able to see whats in parallel, and perhaps where the delays are.

15:36 rhickey: get the with-opens in there or your connections aren't getting closed

15:39 gnuvince: rhickey: I did.

15:39 Followed the code of slurp almost verbatim.

15:40 rhickey: you aren't doing Chouser's line-seq stuff?

15:40 apply str wraps all the stringbuilder junk

15:41 gnuvince: No, I don't have the contrib directory.

15:42 Chouser: Unless you know otherwise, I'd be suspicious of startup time -- some people have reported as much as 4 or 6 seconds in some configurations.

15:42 rhickey: everything except ds/reader is default Clojure, just put your reader there

15:43 gnuvince: Chouser: doing my testing in the REPL

15:46 Do you guys want to see the whole thing? I could be *way* off.

15:50 Chouser: gnuvince: feel free to paste it.

15:51 lisppaste8: gnuvince pasted "Comic fetcher" at http://paste.lisp.org/display/68064

15:56 gnuvince: How does that look?

15:57 scottj: Is clojure-contrib included in clojure or do you have to download it separately from its SF page?

15:57 abrooks: scottj: http://sf.net/projects/clojure-contrib

15:58 (It's separate.)

16:00 wwmorgan: gnuvince: you might get better performance if you use the byte array input stream read methods instead of the single byte method

16:01 duck1123_: if I have a clojure script in a file that I execute using the shebang trick, does that compile it every time, or is something cached?

16:01 Chouser: you want send-off instead of send, since fetch-comic can block.

16:01 duck1123_: and if the former, can it be compiled for later use?

16:01 Chouser: duck1123_: compiled every time. There's currently no way to "cache" compiled clojure code.

16:02 scottj: abrooks: thanks. There are no installation instructions right?

16:02 Chouser: scottj: just unpack it somewhere and add clojure-contrib/src to your java classpath.

16:02 gnuvince: Chouser: is an agent the correct type of reference to use?

16:03 abrooks: scottj: Not that I'm aware of just use ant/mvn the same way you build Clojure and do what Chouser said.

16:03 ^of^of --

16:03 Chouser: you don't have to build clojure-contrib at all, afaik.

16:04 abrooks: Chouser: Really? Hm. I did.

16:04 I guess you wouldn't have to. I build a jar and point my classpath to that.

16:05 Much better to point to the live files though...

16:06 jao: has clojure an equivalent to scheme's letrec or cl's labels?

16:09 Chouser: jao: you can put a name a fn so: (fn foo [] ... (foo ...))

16:09 hopefully the clojure makes sense even if my english didn't.

16:10 jao: Chouser, mutually recursive ones?

16:10 Chouser: gnuvince: yeah, I think an agent is fine

16:10 gnuvince: OK

16:10 Chouser: jao: no, that name is only good inside the fn

16:10 gnuvince: And I think the reason it is slow is that www.comics.com seems to load *really* slowly on this machine.

16:11 Chouser: for mutual recursion, I think you may need (def foo) (defn bar [] ...) (defn foo [] ...)

16:11 gnuvince: On another machine (with a different ISP), the entire source loads instantly

16:11 jao: Chouser, i see. thanks.

16:12 Chouser: gnuvince: using send instead of send-off means you were using a pool of threads sized based on your number of CPUs.

16:12 gnuvince: and with send-off?

16:14 kotarak: jao: but mutual recursion is not a good idea in Clojure due to the limitations of the JVM concerning TCO.

16:16 jao: kotarak, which is a pity :)

16:16 Chouser: send-off gets threads from a pool that grows as needed.

16:16 kotarak: jao: according to Rich a lot of people complained at the JVM Summit. Maybe there will be some change soon. :)

16:17 * jao hopes for the best :)

16:17 Chouser: kotarak: good point, although using lazy-cons or something similar can still require the (def foo) but not threaten the stack.

16:17 kotarak: Chouser: yep. have to work more with lazy-cons, me thinks...

16:17 * kotarak wishes, he were a little brighter...

16:20 Chouser: gnuvince: so you're happy with your code's performance now?

16:20 jao: (although i think mutual recursion would be useful even without TCO in some cases; after all, CL doesn't ensure TCO and has labels.)

16:23 gnuvince: Chouser: I'll try the code on my machine at home and see if it's indeed something with my workplace's network that's causing the delay.

16:28 Chouser: gnuvince: I don't think that's parallel. You're sending fetch-comic to the same agent, so it'll do them in series.

16:29 you'd need a new agent for each fetch-comic, and probably a ref to help you coordinate the results.

16:29 gnuvince: agents to send-off x fetching threads and use commute to accumulate them into a vector?

16:30 Chouser: yeah, I think that would do it.

16:30 gnuvince: OK.

16:30 I'll look into it.

16:30 Chouser: (doseq c coll (send-off (agent nil) (collect-comic c))) or something

16:31 where collect-comic would call fetch-comic and do the dosync commute stuff.

16:31 gnuvince: Is this channel logged on ircbrowser.net or something?

16:31 Chouser: http://clojure-log.n01se.net/

16:32 gnuvince: Good

16:32 thanks

16:32 In case I need to review this conversation.

16:33 wwmorgan: chouser: does (collect-comic c) belong in its own S-expression there?

16:35 or would (doseq c coll (send-off (agent nil) collect-comic c)) make more sense?

16:35 Chouser: wwmorgan: nope, you're right.

16:36 or perhaps (send-off (agent c) collect-comic)

16:49 scottj: gnuvince: I would be interested in seeing your finished code.

18:03 danlarkin: So in boot.clj (http://clojure.svn.sourceforge.net/viewvc/clojure/trunk/src/clj/clojure/boot.clj?revision=1052&view=markup) on line 1267 the filter function is defined. Why won't that blow the stack, since it will recurse without using recur

18:05 rhickey: danlarkin: that call is in a lazy-cons, which suspends the expression until needed

18:06 danlarkin: but when I evaluate it with a huge list doesn't it have to keep all that stack info around?

18:07 rhickey: danlarkin: there's no stack info, filter returns without that second call happening. Later, if someone calls rest, that call will be made, retuning another lazy cons. They don't build up on the stack, there is no recursion

18:16 danlarkin: ah ha, I think I understand. (rest (filter ...)) is a clojure.lang.LazyCons datastructure, it doesn't just call up the (cons..)

18:49 alec: I'm trying to get Lucene working from Clojure. There's a class Field.Index under org.apache.lucene.document, but when I (import '(org.apache.lucene.document Field.Index)), I get a class not found error. Fiddling with it a bit doesn't help me load the class, and I'm guessing it's the '.' in there. Any suggestions?

18:50 rhickey: Field$Index

18:50 alec: thanks, that worked!

18:51 I don't see that on the Java interop page; is there somewhere else I should have looked?

18:52 rhickey: no, it's just a Java thing, that's the real JVM name for a nested class

19:49 lisppaste8: johnwayner pasted "gen-class with main issue" at http://paste.lisp.org/display/68077

19:51 johnwayner: I'm trying to figure out how to define a main for a gen-class, but I can't seem to get it to work.

19:51 I've tried looking through the gen-class function, but I can't quite figure out what the problem is.

19:53 Also, I was wondering if there's a reason gen-and-save-class doesn't create the directory structure. It seems simple enough which is why I think there must be a more compelling reason. (.. file getParentFile mkdirs)


19:53 Chouser: johnwayner: try (defn Test-main ...)

19:54 johnwayner: I tried that... But I'll try agin

19:54 Chouser: hm, not sure...

19:54 johnwayner: yeah, same result

19:57 Chouser: works for me

19:57 no, something's screwy. hang on

20:04 ok, I'm seeing your error.

20:04 I don't think I've ever used :main correctly.

20:05 johnwayner: there's not much on the web that I could find

20:05 what do you see?

20:06 Chouser: exactly what you posted.

20:06 johnwayner: Ohhhhh

20:07 I thought you meant that you saw what I was doing wrong :)

20:07 Chouser: also I put (prn :loaded) in the .clj, and I'm not seeing that, so I don't think it's finding the .clj file correctly.

20:07 ah, sorry. :-/

20:08 johnwayner: what do you mean by finding the .clj file? When does it do that? Does the class file need to find the clj?

20:09 If so, I've completely got the purpose of gen-class all wrong :)

20:10 Chouser: gen-class generates a little stub .class -- the implementation of each generated method just turns around and calls the clojure function in the .clj file.

20:10 this allows you to swap out implementations at runtime, just like regular clojure functions.

20:10 johnwayner: hmmm....

20:13 jeez... it says that right there in the first paragraph of the doc string.

20:14 I've copied my Test.clj to the .class location but I'm getting the same result still.

20:14 I'm assuming that's what you did in the first place :)

20:15 Chouser: ok, :main is broken. But not broken enough to be causing your problems.

20:16 johnwayner: ha

20:16 Chouser: I honestly didn't know what it was for, so thanks for your example. :-)

20:17 ok, so until gen-class is fixed, the name of the fn should be just "main"

20:17 strike that

20:17 gah, I'm confusing myself.

20:19 johnwayner: Thanks for your help. I've got to run for a while, but I'll check back later. Please just respond here if you come up with anything.

20:19 Chouser: "Test-main" is right, it's the error messages that are wrong.

20:19 johnwayner: ok, np.

20:20 johnwayner: oh...I should try that now that I know that the clj is needed...

20:20 hey hey

20:21 airty issue...but it found the fn

20:21 Chouser: oh!

20:21 well, you're ahead of me then.

20:21 johnwayner: got it

20:21 changed it to no args

20:22 I'll annotate.

20:22 lisppaste8: johnwayner annotated #68077 with "fixed." at http://paste.lisp.org/display/68077#1

20:23 Chouser: great, thanks.

20:23 johnwayner: thank you!

20:23 I was in left field with my thinking about all this.

20:23 Ok... gotta run.

Logging service provided by n01se.net