#clojure log - Dec 22 2008

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

0:03 hiredman: the hard drive in the machine that was running clojurebot died

0:24 Chouser: hiredman: :-(

0:25 hiredman: it maybe a week or two before it gets rebuilt

0:50 joha1: would like to get unbuffered console input (e.g. pressing a key should return at once, instead of waiting for ENTER), preferably without having to use something big like JCurses. So far I'm failing. Any ideas?

0:56 Chouser: joha1: in C you'd use tcsetattr to set the terminal's parameters

0:58 joha1: yes, I tried something similar with stty (I'm on Linux). Didn't work, but perhaps my mistake

0:59 Chouser: ah, shelling out to stty?

0:59 that rings a bell...

0:59 joha1: well, I couldn't make it work, but perhaps you have seen something similar?

1:00 Chouser: not from java/clojure, but I'm pretty sure I've done it. maybe from perl?

1:00 joha1: Hmm, perhaps I should google a bit more. I already tried "stty -icanon min 1"

1:05 Chouser: try adding "time 0" to that

1:11 I don't think that's it.

1:12 you're using Runtime's .exec method?

1:19 joha1: chouser: yes i am

1:19 must be a better way

1:19 Chouser: ok, the problem is that the sub-process is run in a way that's not associated with the terminal

1:20 joha1: makes sense

1:20 Chouser: if I add -F /dev/pts/termnum to the stty command line, it works

1:20 so, what to use for termnum?

1:20 I tested by running "tty" on the command line and copying the result into my test program manually.

1:21 but I don't know if there's anyway to get the terminal associated with the java process's stdin

1:22 joha1: running tty from Runtime.exec would give the tty for the new process instead, right?

1:22 Chouser: right.

1:22 trying that got me back the string "not a tty"

1:23 joha1: in worst case I could always to to get JCurses to work. Much overhead for something so simple, though...

1:24 thanks anyway

1:24 Chouser: or use Swing. :-)

1:24 joha1: sure, but sometimes you just need a text console

1:24 :)

1:24 Chouser: I think you mean a JTextPane

1:24 sometimes you just need a JTextPane

1:25 joha1: not if I don't have X on my server

1:25 * Chouser sits in stunned silence.

1:26 zakwilson: People have X on servers?

1:29 Chouser: joha1: you could do the stty setup/teardown in a launching script

1:31 joha1: I've just found a page describing how to set up nonblocking input in Java using the stty method

1:31 http://www.darkcoding.net/software/non-blocking-console-io-is-not-possible/

1:31 will try to get this working in clojure

1:32 but of course I could set it up in a calling script as well

1:36 Chouser: huh, he bounces it through "sh -c ... < /dev/tty" and apparently that does it.

1:39 oh, nope, I screwed up my test.

1:47 joha1: Yeah, this works!

1:47 (import '(jline ConsoleReader))

1:47 (.readVirtualKey (new ConsoleReader))

1:47 and there are lots of other useful functions in Jline

1:47 Chouser: :-)

1:58 lisppaste8: Chouser pasted "unbuffered input at text terminal" at http://paste.lisp.org/display/72515

1:59 joha1: nice

2:00 Chouser: but if jline of jcurses is an option, I'm sure you'll have better results there.

2:01 joha1: it will certainly be easier, and multi-platform. Still interesting to know that it can be done

4:10 klinkers: how fast is Clojure?

4:10 benchmarks?

4:14 leafw: klinkers: as fast as java.

4:15 but, considering it enables better algorithms, your programs may be faster than naive, imperative implementations in java.

4:18 klinkers: enables bette ralgorithms?

4:18 dont yu always have more options in java? you can do inplce sorting etc

4:18 ormaybe you cna in clojrue too

4:19 anyway does AOT mean I can compile to a JAR? and that other java-libs can use my clojure code?

4:19 leafw: yes.

4:26 lisppaste8: leafw pasted "benchmark" at http://paste.lisp.org/display/72517

4:26 leafw: klinkers: have a look for yourself.

4:26 it's a very simple benchmark, adding numbers.

4:34 klinkers: janino?

4:35 clojure wih primitives is that doing things like : (+ (int 5) (int 6)) ?

4:37 leafw: and type declarations.

4:44 klinkers: that is a type declaration no?

4:49 leafw: well, (int 5) is a type declaration indeed, although I can't help thinking of it as a cast (but it isn't)

4:50 although (int 1.5) prints 1.

4:50 "Coerce to int", (doc int) says.

5:00 klinkers: clojure.examples.hello

5:00 is clojure and examples directories then?

5:01 hoeck: klinkers: right

5:02 ./clojure/examples/hello.clj

5:05 klinkers: hmm i use september there fore compiel is not working?

5:06 leafw: klinkers: pull svn

5:08 hoeck: klinkers: or use the clojure pre realease

5:08 (the download link on clojure.org)

6:18 bOR_: Hi all, I ran into: java.lang.Exception: Transaction failed after reaching retry limit (NO_SOURCE_FILE:0)

6:18 and on the forum I see that stuart sierra ran into the same thing, and rich recommended not using a wait function.

6:19 wondered if the official (await ... ... ..) is also a dont-use-this-in-very-long-loops wait function

6:19 http://groups.google.com/group/clojure/browse_thread/thread/c8c3510f01f951e1/a2b74c4fd85c89bb?lnk=gst&q=retry+limit#a2b74c4fd85c89bb

6:22 it seems that all elements in my vector of refs are locked now.

6:22 mm.

6:23 fyuryu: bOR_: I can't really answer your question, never encountered the problem so far, but try asking in a couple of hours (5-6)

6:23 bOR_: and a source snippet would help

6:23 bOR_: I'll drop it into the forum then.

6:26 fyuryu: try structuring the code differently, waiting in a loop doesn't seem like a goo idea (but without knowing what you want to do exactly, it's hard to tell)

6:26 maybe agents would be a good fit for you task?

6:29 bOR_: oh wait, you're using await in that loop?

6:35 jgracin: replaca: fantastic job on cl-format! I was hoping someone would do it eventually, and this was quick.

6:43 bOR_: (sorry, was cleaning my bike). I've 8 agents that each are send off in a loop, at the end of sending them off, I await them all.

6:43 the loop itself is a million times.

6:43 (but I'm not sending off 8 million agents at the same time)

6:43 (just 8)

6:44 each agent has the task of doing 7 things to every reference in a vector, in random order.

6:44 and right now, while we're no longer in a loop or anything,

6:45 I can't even do a single thing to a single ref anymore without it failing due to many retries.

6:45 is there any way to see which refs are all locked right now, and by whom they are locked?

6:54 fyuryu: and how big is the vector that the agents operate on?

6:55 bOR_: vector of 1000 refs

6:56 it's an agent-based model. each ref might contain a host, and the 7 things I'm doing to them are birth / death / evolution / infection.

6:57 thanks for talking though, will help in knowing what information to put in the google group post.

6:58 fyuryu: bOR_: I don't think there is a way to see who locks the refs in a given moment

6:59 bOR_: think I know..

6:59 based on doc await.

6:59 if there's one of the transactions not returning.

6:59 await just keeps blocking everything, I guess.

7:00 fyuryu: ah, so you're not sure if every agent completes his work?

7:00 bOR_: as await might still be waiting for one of the (send-off) to finish.

7:00 normally it should.

7:00 and it tends to

7:01 but maybe if for some reason I don't know yet, one of the send-off agents blocks.

7:01 ok..

7:01 that's a good question.

7:01 what happens with await, when one of your threads runs into the retry limit.

7:02 fyuryu: (doc await-for)

7:02 bOR_: gracias. that might work indeed.

7:02 normally, a single year takes about 60 seconds to compute.

7:03 well, sometimes 90

7:03 so I can just put the await on 3 minutes.

7:04 I'll make a post, cause I wonder what happens with the thread that didn't return on await.

7:24 klinkers: im trying to compile but the examples are not so easy

7:24 ok i have a file C:/clojure/progs/hello.clj

7:24 how would I compile it?

7:24 hte namespeace should contain :gen-class?

7:24 and the compeltr apth?

7:25 leafw: klinkers: http://pacific.mpi-cbg.de/wiki/index.php/Clojure_Scripting#Generating_java_classes_in_.class_files_from_clojure_code

7:26 klinkers: http://clojure.org/compilation

7:49 klinkers: yes but what im wondering voer is namespaces

7:50 if i ahve a file

7:50 C:/clojure/progs/hello.clj

7:50 what namespace should i put it in?

7:51 Chouser: klinkers: they only way for that path to be a valid lib would be if it has the namespace progs.hello (and C:/clojure is in your classpath) or the namespace clojure.progs.hello (with C:/ in your classpath)

7:54 klinkers: i have C:/clojure in my classpath and I have the file int he namespace progs.hello

7:55 i do (compile 'progs.hello) and i get:

7:55 java.io.IOException: The system cannot find the path specified (hello.clj:1)

7:55 user=>

8:00 fyuryu: klinkers: "progs.hello" namespace == "c:/some-path/progs/hello.clj", and c:/some-path AND c:/some-path/classes must be in your classpath.

8:04 klinkers: java.io.IOException: The system cannot find the path specified (hello.clj:1)

8:04 progs.hello=>

8:04 what is classes there btw?

8:04 the classes it uses u mean?

8:05 Chousuke: klinkers: the classes dir contains the compiled code

8:05 or will contain

8:05 it needs to exist and be in the classpath before compilation though.

8:05 klinkers: http://hpaste.org/13252

8:06 Chousuke: which I think is not very nice, but I don't know a way around it either.

8:06 klinkers: should it be called classes?

8:07 Chousuke: klinkers: you don't need str with println btw.

8:07 it can take multiple arguments.

8:07 acieroid: how can I cast an Integer to a Char with clojure ?

8:07 klinkers: still: progs.hello=> java.io.IOException: The system cannot find the path specified (hello.clj:1)

8:08 Chousuke: you'll want your classpath to contain C:/clojure/;C:/clojure/classes/

8:09 along with the others

8:09 and remove the entry with hello.clj in it

8:09 kogu: acieriod: char?

8:09 acieroid: hum

8:09 forgot this function ><

8:09 Chousuke: klinkers: and make sure C:/clojure/classes/ exists

8:10 kogu: ok, im really new to lisp, can someone help me with this really basic thing?

8:10 http://hpaste.org/13253

8:11 it always prints 0

8:11 klinkers: you should use if

8:11 instead of when

8:11 i think

8:11 acieroid: no

8:11 Chousuke: no

8:11 acieroid: because data are immutables

8:11 klinkers: yes and branch

8:11 Chousuke: kogu: + does not change points

8:12 klinkers: ah ysw recur points

8:12 Chousuke: kogu: it only outputs a new value, which is promptly discarded

8:12 kogu: i see, so how can i use a global variable for points?

8:12 acieroid: with refs

8:12 rhickey: could everyone please use paste.lisp.org please? then we get a single archive to look back through

8:13 lisppaste8: url

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

8:13 Chousuke: kogu: once you (let [points 0]) points is 0 and will not change

8:13 kogu: ok, so how do i define a variable which will change

8:13 Chousuke: kogu: for that code, you don't.

8:14 kogu: simply modify the logic to call recur in a way that passes the change to the next loop :)

8:14 kogu: ah i see, that makes sense, thanks a bunch, emacs you bastard, here i come

8:14 Chousuke: but if you really need a global "points" state, the way to do that is to use a ref and dosync

8:15 kogu: i haven't gotten to that part yet, but i will keep that in mind

8:15 Chousuke: but surprisingly many apps don't even need refs

8:16 you can also have state as something that is passed to each function and they then return a new state

8:18 kogu: hmmmm

8:18 have to grok it, still think in java

8:18 one more ques, how can i do a lot of if elseif elseif else?

8:19 Chousuke: cond

8:19 kogu: wow, thats right

8:19 ty again

8:21 Chousuke: using (or) can also be useful if you need to stop as soon as you get something non-false

8:23 or returns the first non-false value as is, so the following will work assuming the search function returns nil if an item is not found: (defn get-item [] (or (search source1) (search source2) :default-item))

8:24 klinkers: acieroid: Integer.

8:25 acieroid: klinkers, char works perfect

8:27 klinkers: and it should be c:/clojure/classes/ not c:/clojure/progs/classes or anything?

8:27 progs.hello=> (apply char "2")

8:27 \2

8:27 progs.hello=> (Integer. "2")

8:27 2

8:29 Chousuke: klinkers: yeah, c:/clojure/classes/

8:31 klinkers: so what could i be missing?

8:31 java.io.IOException: The system cannot find the path specified (hello.clj:1)

8:31 i ahve the correct paths in the classpath

8:32 path specified (hello.clj

8:32 should that says the whole pth to hello.clj?

8:32 Chousuke: no.

8:33 does the classes dir exist?

8:33 it must exist when you start the VM

8:33 hoeck: klinkers: have you set *compile-path* to "c:\\clojure\\classes" ?

8:34 Chousuke: shouldn't that be the default.

8:34 klinkers: oh

8:34 where is compile-path?

8:34 where do is et it anyway?

8:34 Chousuke: in your clojure program

8:34 hoeck: it defaults to "classes"

8:35 Chousuke: a simple (set! *compile-path* "c:/clojure/classes") at the top of your script should do I guess.

8:35 klinkers: set! ?

8:36 hoeck: or do (binding [*compile-path* "bla\\foo"] (compile 'clojure.expamples.hello))

8:36 klinkers: u emand ef?

8:37 hoeck: *compile-path* is bound above the repl so you can set! it

8:37 klinkers: im using emacslisp in clojure then?

8:37 Chousuke: no.

8:37 *compile-path* is a clojure setting, not an emacs one

8:38 klinkers: hello mama!

8:38 there it worked

8:38 it egenrates a bunch of .class stuff

8:39 then i can compile that to a JAR with javac!?

8:39 Chouser: I use the 'jar' command to produce a .jar file

8:41 * hoeck admits he uses winrar & drag-drops its own classfiles into the clojure.jar file

8:42 klinkers: exactly how? you mvoe to ~/classes/ and then?

8:43 or jsut form anywhere(mind me i dont know java tow ell)

8:43 kogu: klinkers: you just zip that folder, and rename it's extension to .jar

8:44 klinkers: make sure that the folder path is preserved

8:47 Chouser: kogu/hoek: you can set up the manifest correctly like that?

8:48 kogu: cho: usually if you don't have a main class, you don't need the manufest file

8:48 Chouser: ah, ok.

8:49 klinkers: jars a re zipped .class-collections?

8:49 Chouser: klinkers: yes

8:49 with some (apparently optional) extra header info

8:50 kogu: jars, wars, *ars

8:50 all the same

8:50 klinkers: so i should have another word between progs and the actual program then

8:54 lisppaste8: kogu pasted "untitled" at http://paste.lisp.org/display/72523

8:54 kogu: ummm, how to i return the points from that function?

8:55 Chousuke: kogu: use let instead of def

8:55 kogu: and: (do (println points) points)

8:55 klinkers: kogu: exactly what are yout rying to do? idiomatically you shouldnt use de flike that

8:55 Chousuke: print*

8:56 kogu: cho: print is just for debugging

8:56 cho: im loopping 10 times, creating a new roll each time, eval the roll and adding points accordingly

8:57 Chousuke: kogu: oh right.

8:57 kogu: I misread that thing :P

8:57 use if instead of when then

8:57 Chouser: change your (when (> counter 0) ...) to (if (zero? counter) points (do ...))

8:58 kogu: cho: ah i see, ty, so i change def -> let, and change when->if

8:58 cho: ty

8:58 Chouser: right -- those changes are related, but you need both.

8:58 those changes are NOT related, but you need both

8:59 kogu: cho: right, let because i want it scoped locally, and if to return the points

8:59 Chouser: right

8:59 Chousuke: kogu: (if (> counter 0) (let [roll (new-roll)] (print points) (recur (dec counter) (+ points (eval-roll roll)))) points)

8:59 parentheses may not match...

8:59 Chouser: well, also 'let' because 'def' inside a function like that is icky.

9:00 hoeck: kogu: or do (reduce + (take 10 (repeatedly new-roll)))

9:04 Chousuke: or because you need eval-roll: (reduce + (take 10 (repeatedly #(eval-roll (new-roll)))))

9:05 kogu: cho: whoa!!!

9:05 let me try that

9:14 cho: dude! that was awesome, that worked like a charm

9:17 Chousuke: it was hoeck's idea though. I just fixed it to match your code. :)

9:18 often you can use the higher-order functions and reduce instead of explicit loops.

9:19 kogu: cho: well i got both working, i need to look into this reduce, never used this before

9:20 * hoeck was a LOOP follower some time ago, now he believes in map, filter and reduce

9:23 Chousuke: kogu: reduce is a function which takes a function of (at least) two arguments and a sequence, then applies that function to the first two values of the seq, then again to the result and the next value in the seq, etc.

9:24 kogu: hmmm, never thought it could be used like this

9:24 Chousuke: so (reduce + [1 2 3 4]) = (+ 4 (+ 3 (+ 1 2)))

9:24 kogu: btw, anyone using clojure-mode on emacs here? how to see which parens does the parens under the cursor match to?

9:24 hoeck: kogu: i recommend the http://clojure.org/sequences page for an overview over the sequence library, though you may just use (doc reduce) at the repl

9:25 kogu: will read it, right now

9:25 Chousuke: but of course works with any function

9:25 for example, to find the max value of a sequence: (reduce #(if (< %1 %2) %2 %1)) []

9:26 oopw

9:26 well something like that

9:26 jdz: kogu: that's an emacs configuration option, "paren match highlighting" in options menu

9:26 Chousuke: does anyone know how to make emacs emit only spaces instead of tabs?

9:26 I noticed mine emits tabs and that screw up formatting sometimes.

9:27 jdz: Chousuke: indent-tabs-mode

9:27 (set it to nil ;)

9:27 hoeck: (setq-default indent-tabs-mode nil)

9:27 but mine is an xemacs

9:27 jdz: yes, M-x customize-variable intent-tabs-mode

9:29 Chousuke: the customisation facilities in emacs are awesome

9:30 maybe a bit too awesome

9:30 there's so much to customise it can be difficult to find the relevant stuff

9:31 * kogu emacs rules!!!

9:31 hoeck: but you can do <tab> and look at the autocomplete buffer

9:32 i whish i could do this in the crappy powerbuilder ide i have to use at work :(

9:36 klinkers: nice

9:36 bOR_: Hi rhickey, working on a reproducable version that doesn't take 3 hours on 8 cores :)

9:37 posted the source online.

9:38 klinkers: when will v1.0 of clojure come out?

9:38 bOR_: as long as none of you here are in the competitive field of doomsaying, I shouldn't get into trouble of sharing it here.

9:40 hoeck: klinkers: http://groups.google.com/group/clojure/browse_thread/thread/381e575bad1cfb77

10:00 rhickey: bOR_: I put up a rev that might help your problem - I think once you started failing you might have quickly wrapped the timestamp - now an AtomicLong in svn 1181

10:01 bOR_: thanks.

10:01 not sure I understand.

10:01 what you mean with wrapped the timestamp / now an AtomicLong.

10:02 kogu: rhickey : thank you for clojure

10:02 rhickey: bOR_: was an AtomicInteger - but once you started failing and let the sim continue you'd consume timestamps at a high rate

10:02 kogu: you're welcome!

10:02 bOR_: ok.

10:03 the high rate was 1.8 seconds? ("Elapsed time: 1871.911 msecs" )

10:05 rhickey: bOR_: that would explain your locked up situation afterwards, but you probably still have some bad transaction granularity.

10:06 bOR_: hehe. getting something to run concurrent in clojure is easier than understanding all the things that go wrong. Reading up on transaction granularity now. I'll just see if I can make a version of the model that quickly produces the error.

10:09 I'll see if I can reduce it somehow.

10:11 from birth: (let [living (apply vector (gather :born))

10:11 ah.

10:11 rhickey: right

10:11 bOR_: birth is doing a gather of all living.

10:11 and gather will be locking the whole thing.

10:11 rhickey: that's the gather I saw

10:11 bOR_: the rest almost only messes with a single ref.

10:12 rhickey: bOR_: it won't be locking, as it is only a read, but it will increase the footprint of the world snapshot required for that dosync

10:13 bOR_: ah.

10:14 but if that is just a memory thing, I seem to have enough memory.

10:14 for a moment thought it would be locking, but it is indeed only reading, and using a snapshot of what once was a father ;)

10:16 at most I'm doing 8 births at the same time in the whole population. that doesn't seem too bad.

10:16 (8 processors)

10:27 klinkers: how can i remove a namespace from the repl?

10:28 hoeck: (doc remove-ns)

10:28 klinkers: and how do I require my user-file? do i have to put it in a namespace?

10:29 but the repl still says the old namespace...

10:35 kogu: what's the opp of "nil?"

10:37 Chouser: kogu: depends, but generally 'seq' or just the object itself

10:37 s/generally/usually/

10:39 kogu: cho: its a number, hmmm

10:39 (defn eval-roll [roll]

10:39 (let [payout (odds roll)]

10:39 (if (nil? payout) -1 (- payout 1)))

10:39 where "odds" is a map

10:39 Chouser: you want to know if the map is empty?

10:40 Chousuke: payout is a number?

10:40 kogu: no, if i don't know have the key in the "odds" map, i get back null, which throws nullpointer

10:40 in if(payout)

10:40 Chousuke: kogu: you could use (get odds roll 0)

10:40 for a default value

10:40 Chouser: right, or just (odds roll 0)

10:43 kogu: (defn eval-roll [roll]

10:43 (let [payout (odds roll 0)]

10:43 (if (payout) -1 (- payout 1))))

10:43 Chouser: no

10:43 (defn eval-roll [roll] (- (odds roll 0) 1))

10:44 kogu: yeah, that makes more sense

10:44 ty again

10:44 Chouser: but in the general case of wanting to handle a failed lookup separately, by default map lookups return 'nil', which in an 'if' means the same as false.

10:45 so: (let [payout (odds roll)] (if payout (- payout 1) -1))

10:45 Chousuke: note no parentheses around payout. :)

10:45 kogu: ah, that was where i was stuck

10:45 Chouser: or: (if-let [payout (odds roll)] (- payout 1) -1)

10:47 kogu: cho: final question for you, I have a list of 2 random numbers, i have a odds table like this

10:47 (def odds {'(5 5 5) 25 '(4 4 4) 5 '(3 3 3) 5 '(2 2 2) 5 '(1 1 1) 5 '(0 0 0) 5})

10:48 now i need to check if i have 2 zeros 1 non zero

10:48 what would be the lispy way todo this

10:49 as i need to check for (0 0 *) (0 * 0) and (0 0 *)

10:49 Chouser: you have a list of 3 numbers?

10:49 kogu: yes, i have a list of 3 numbers (0-5 0-5 0-5)

10:50 for checking 3 numbers i made a map above

10:50 Chousuke: (= 2 (count (filter zero? triple))

10:50 )

10:50 * Chouser concurs

10:51 Chouser: though I had: (= '(0 0) (filter zero? triple))

10:52 kogu: yes, that works perfectly

10:53 infact thats a better approach than the map for the 3 identical values

10:53 ty again

10:54 any fucntion to check if all values are identical?

10:54 Chouser: (apply = coll)

10:55 Chousuke: heh.

10:57 many of these solutions have the "d'oh" look to the

10:57 tem

10:57 ...

10:57 them

10:57 kogu: (defn eval-roll [roll]

10:57 (cond

10:57 (apply = roll) 25

10:57 (= 2 (count (filter zero? roll))) 10

10:57 (= 1 (count (filter zero? roll))) 1

10:57 () -1))

10:57 how does this look

10:57 i think im done

10:58 Chouser: use :else instead of ()

10:58 kogu: done

10:58 time to benchmark against the java code, woohoo!!!

10:59 Chouser: you're sure it matters?

10:59 Chousuke: kogu: most likely it'll be a fair bit slower :)

11:00 Chouser: the most important benchmark is LOC, or some more reliable measure of mental complexity.

11:00 Chousuke: benchmarking might make java look good but does the *code* look as good as the clojure equivalent?

11:00 or "equivalent" :/

11:02 kogu: loc : 18 vs 57

11:02 Chouser: I wonder if condp would help here. I have no sense of how to use its features yet.

11:02 kogu: ah, nice. That's worht so much more than 5 seconds vs. 1 second of processing time, or whatever.

11:03 kogu: speed : 7 sec vs 2, that's not bad

11:03 cho: ty again, you are truly awesome

11:04 Chouser: you could get back some or all of that speed, but it would start to cost you in code clarity

11:06 danm_: good morning

11:08 kogu: gm

11:15 any recommended profilers for clojure?

11:44 RSchulz: YourKit is what I use, though I've yet to apply it to Clojure code.

11:44 kogu: ^^^

11:44 kogu: rs: ty

11:45 does anyone of anywork on something like jsp's for clojure?

11:45 as in, compile to servlets

11:46 duck1123: kogu: there's been varying amounts of success with compojure

11:46 kogu: i did look into compojure, but right now there is no mention of any templating system

11:46 its much better to write html and embedd lisp rather than the other way around

11:47 duck1123: it uses compojure.html to generate html from vectors

11:48 kogu: duck: yeah, but i would like to write html file, and embedd bits of lisp in it

11:48 duck1123: There was a thread recently on that subject, I don't know how far anyone got

11:49 kogu: cool, let me dig that up

11:49 hiredman: ugh

11:49 why would you want to write any html at all?

11:50 kogu: hehe, work!!!

11:51 is jvm good for anything else?

11:51 Chousuke: s-expressions map nicely to HTML anyway

11:51 qebab: hey, is it possible to use keyword params or optional params?

11:53 duck1123: kogu: http://tinyurl.com/7vlcj6

11:53 kogu: step 1: download free html template

11:53 step 2: write clojure blogging system

11:53 step 3: ???

11:53 step 4: profit!!!

11:53 hiredman: sounds horrible :(

11:54 Chouser: qebab: http://groups.google.com/group/clojure/msg/51bb53ca077154f8

11:54 hiredman: compojure's vector -> html deal is great

11:54 * arbscht_ seconds that

11:55 Chouser: qebab: that's some old code, so it could probably be written more concisely now. But at first glance it looks like it would still work.

11:58 qebab: Chouser: I don't really need it, I just think it'd be convenient. :)

11:58 Chouser: Thanks, though.

11:58 Chouser: if you just want some keyword args tacked on the end of zero or more positional args, you can do it in about one line

12:02 (defn foo [a b c & keyargs] (let [{:keys [d e f]} (apply hash-map keyargs)] [a b c d e f]))

12:02 (foo 1 2 3 :e 9) ==> [1 2 3 nil 9 nil]

12:39 daswerth: Chouser: yesterday you wrote up something on unbuffered input to a text terminal: http://paste.lisp.org/display/72515

12:39 Chouser: yep

12:40 daswerth: I'm afraid I don't understand why there are to defn's for "system"?

12:40 Chouser: just a pasting mistake on my part. The first is overridden by the second.

12:41 as in, replaced. The first is completely unnecessary.

12:41 daswerth: ah, great. :)

13:30 klinkers: booya clojure is awesome

13:30 zakwilson: We've noticed. That's why we're here.

13:30 klinkers: a nice fairly pure functional language + a lot of good javalibs

13:31 anyone working on machine learning stuff?

13:31 Chouser: people seem to ask about genetic programming a lot

13:31 klinkers: i working on webapp/mobile app using machine elarning for secret stuff and great profits!

13:32 maybe i will eb the first big clojure success story

13:33 Kerris7: I've been tinkering with the idea of writing a Chinese Chess a.i. in Clojure

13:34 should make for a decent final year project, but the other candidates are quite strong (Scala)

13:36 klinkers: final year of what?

13:37 undergrad?

13:37 i wrote an optimal-playing tictactoe in clojure but chinese chess is a little harder :)

13:38 Kerris7: klinkers: undergrad

13:43 klinkers: yes, a little harder :P http://en.wikipedia.org/wiki/Xiangqi

13:44 Chouser: Kerris7: I was learning Scala before I abandoned it for Clojure, in case that's worth anything to you.

13:45 Kerris7: Chouser: I'm working on a portfolio that'll hopefully admit me to a good Master program and the existing material for that domain is mainly in OCaml

13:46 Chouser: Kerris7: ah. sounds like you may have significantly different goals than I had.

13:46 Kerris7: Chouser: if you don't mind me prying, what were your intentions?

13:46 Chouser: for a masters program, Clojure's non-invasive type system may look less impressive.

13:48 Kerris7: For years I'd been looking for a practical language that was very "expressive", or at least that's the term I generally use.

13:50 Kerris7: alright

13:50 Chouser: ...which means something along the lines of getting the most done with the least amount of code, where the things being done are the sorts of things python and ruby have been good at: command-line tools, data and string wrangling, web apps, etc.

13:50 gnuvince: Hehe

13:50 technomancy: heh; I guess for education purposes, Scala has the advantage of looking more impressive since the type system is harder to use. =)

13:50 Chouser: technomancy: exactly what I was thinking.

13:50 gnuvince: "Dude, Clojure is too easy, no way you're getting that Masters Degree!"

13:51 Throw in partial continuations and amb in there to make it look more impressive

13:51 Chouser: I was skating through project euler problems in Scala, liking it just fine.

13:52 Then I tried to write a nice API (a.k.a. embedded DSL) for querying XML documents.

13:52 gnuvince: Didn't like it so much then?

13:52 Chouser: the type system bit me hard. I was trying to use the code as I wrote it to help me think about the problem. When I got it into a state that seemed to express what I wanted, I still couldn't test it because my types were all messed up.

13:53 I spent a few days trying to get my trivial 4 or 5 function system to actually compile.

13:54 and even then the lack of macros meant my API wasn't as tidy as I wanted.

13:54 Kerris7: If I can find sufficient material on writing lexers with Lisp maybe I can muster up something with Clojure

13:55 Chouser: Anyway, a couple rhickey videos later, and I'd found a new home here. The result a similar project in Clojure is at clojure.contrib.zip-filter

13:56 gnuvince: Chouser: are you a Java refugiee?

13:56 Chouser: not really. I learned Java a tiny bit ages ago -- actually learned threading in Java -- but I've never liked it much.

13:57 gnuvince: ok

13:57 I'm thinking I should probably learn Java

13:58 Chouser: I was giving the JVM a chance because Yegge talked me into Rhino, shortly before Project Euler talked me right back out of it.

13:58 gnuvince: Rhino...

13:58 *meh*

13:59 * technomancy started on the JVM with JRuby

13:59 Chouser: Well, I thought I wanted an optional type system and C-like syntax.

13:59 gnuvince: Is there a Java library to do like Python's struct.pack and struct.unpack?

13:59 technomancy: the way they promoted it early on was pretty weird--hey guys, you can use all these awesome Java libraries and package stuff up as a WAR file.

13:59 gnuvince: Nobody really wants C-like syntax; people just think they want it.

13:59 Chouser: gnuvince: for C library interop, or more general binary data packing?

13:59 technomancy: and Ruby users look at the Java libs, and they have uniformly horrible APIs... and we have no idea what a WAR is, but it sounds violent.

14:00 so it was hard to get excited about JRuby at first. =)

14:00 hiredman: technomancy: but uniformly documented

14:00 gnuvince: Chouser: general binary data unpacking

14:01 Chouser: gnuvince: ah, don't know. sorry.

14:01 technomancy: hiredman: you only have to learn a library once; you have to deal with the API forever. =)

14:01 gnuvince: Chouser: thanks

14:01 hiredman: technomancy: you just deal with the api long enough to wrap it with something more sane

14:02 javadoc is a life saver

14:02 technomancy: well, the only Java libraries I've used have been jakarta httpclient (wretched, horrible API) and ROME (decently usable, but the docs weren't very good)

14:03 why you'd name a library after Jakarta is beyond me; I've been there, and it's a pretty miserable city.

14:04 hiredman: maybe that is why they renamed it to apache commons

14:04 Kerris7: maybe it was mainly developed by programmers from the city :V

14:06 leafw: likely it was chosen beause of the 'j' in the name.

14:06 hiredman: heh

14:06 lisppaste8: drewr pasted "atom exception -- how is this possible?" at http://paste.lisp.org/display/72540

14:06 technomancy: leafw: probably. It's a good warning for what happens when you pick a name without doing research first.

14:07 drewr: I think there's either a bug in atom or swap!.

14:07 hiredman: someone in #java just asked about a "macro system" for java, and someone said "macros are for desktop apps like word and excel or for editors."

14:07 drewr: Somehow iref is nil in get-validator.

14:07 Chouser: drewr: got any code to reproduce it?

14:08 technomancy: heh

14:08 leafw: hiredman: difficult to preach to the blind.

14:08 Kerris7: or the deaf

14:08 drewr: Chouser: I'm trying to distill. My smaller test cases aren't triggering it.

14:08 Chouser: drewr: are you using validators?

14:08 drewr: I thought I would start with the exception first, because it's pretty strange.

14:10 Chouser: drewr: I can replicate the top 3 lines of that stack trace with: (swap! nil inc)

14:11 lisppaste8: drewr annotated #72540 with "possible sample code" at http://paste.lisp.org/display/72540#1

14:13 Chouser: drewr: so if your agent's map ever loses its :foo key, you'd get that exception.

14:14 drewr: Chouser: I'm trying to see if that happens.

14:15 Dangit, it's nil. This thing is supposed to be immutable! :-)

14:17 Chouser: hm, the agent? not likely. :-)

14:17 technomancy: has anyone here tried hashdot? (http://hashdot.sf.net) it seems to make the JVM CLI experience somewhat less onerous.

14:17 drewr: Chouser: No, the map :-)

14:41 gnuvince: How come (reduce str xs) is so much slower than (apply str xs)?

14:42 hiredman: str makes stringbuilders I believe

14:43 so reduce ends up instanciating a lot more objects

14:45 gnuvince: How does apply avoid that?

14:48 rhickey: gnuvince: a single call to str creates one StringBuilder, and apply is a single call to str

14:48 reduce is many calls to str

14:50 gnuvince: apply creates a single StringBuilder and calls .add() (or whatever the name is) n times while reduce creates n StringBuilders and calls .add() only once on those?

14:52 rhickey: gnuvince: it's best to forget about str - apply calls a fn once with a sequence of args, reduce calls it once for each pair of elements. str optimizes the concatenation of its args, but can't across calls

14:55 gnuvince: ok

14:55 hiredman: the "namespaces, keywords, and symbols" looks like it might need a faq entry

14:57 duck1123: Does anyone know if a SVG version of the clojure logo exists?

14:58 RSchulz: hiredman: Whatever makes you think that??

15:01 hiredman: :P

15:16 hoeck: duck1123: clojure-glyph.svg in the files section of the google group

15:21 Chouser: it only seems complicated if you try to think about it

15:22 hiredman: Chouser:?

15:22 Chouser: namespaces, vars, symbols, keywords. They all work very naturally almost all the time.

15:23 hiredman: yes

15:23 I don't mean it is complicated, I mean there are two different threads in group about it, so maybe it is a faq

15:23 Chouser: it's only when you try to think about edge cases or unusualy usages that it starts to seem complicated.

15:23 oh

15:27 it does seem a bit hard to pin down what should go in a faq vs. an appropriate place in the regular docs.

15:29 hiredman: well

15:29 things that are asked about frequently can go in the faq?

15:29 Chouser: if the docs were complete, would they still be asked about frequently?

15:30 hiredman: the only way to find out is to complete the docs

15:30 Chouser: if I want to learn about topic X, do I need to read it's section in the regular docs plus in the FAQ in order to get a complete picture?

15:32 hiredman: if the docs clear it up, and people stop asking about it, it can be removed from the faq

15:32 it's not like this is being carved in stone, it's html

15:38 technomancy: is it safe to say atoms are meant for idempotent actions?

15:40 Chouser: not necessarily.

15:41 Someone mentioned on the group the function of generating unique ids, where skipping an id is acceptible. atom would work fine for that.

15:42 technomancy: that makes sense

15:47 klinkers: if i have a file main that uses the namespace progs.someapp.donkey and progs.someapp.horse and they both happen to have a function group-by. now, how do i refer to each group-by in main?

15:49 Chouser: if you try to (use ...) both of them, it should complain on the second one.

15:52 klinkers: so you can either do (use '[progs.someapp.horse :rename {group-by horse-group-by}])

15:53 or (require '[progs.someapp.horse :as horse]) and say (horse/group-by ...)

16:47 hiredman: why don't explanations of what a monad is make sense?

17:04 Chousuke: hiredman: actually, reading through the wikipedia explanation I think I can see some sense in it.

17:05 hiredman: then you are a better man than I

17:06 Chousuke: hiredman: it seems monads can be used to specify semantics to computations without affecting the "functional" nature of the values those computations return

17:06 hiredman: *woosh*

17:07 Chousuke: I think the Maybe monad is pretty simple to understand: the computation can fail, so the Maybe monad wraps the value in something that can tell you whether it failed or not.

17:07 amit_: any idea why i might get an IllegalAccessError trying to invoke a constructor for a java class even though I'm able to import it succesfully ? (I'm on the clojure prompt)

17:08 Chousuke: but if it doesn't fail, the result is safe to extract from the monad and treat as if it were just another value

17:08 hiredman: sounds like Just Another Object

17:11 Chousuke: for IO I guess the IO monad "describes" the IO required to get the value (a string, for example), but once you have the value and have extracted it from the monad, it's immutable just like any other value

17:11 so monads give you a way to explicitly define that something else than just functional value computation is going on, and work with that.

17:12 hiredman: uh huh

17:50 drewr: Is there any way I can get @@(send-off (agent :a) (fn [x] (send-off (agent :b) (fn [y] y)))) to work?

17:50 Work == return :b immediately.

17:52 Chouser: you want the top-level expression to not return until both agents have updated their status?

17:53 s/status/state/

17:53 drewr: Yes, that would be ideal.

17:54 Chouser: using agents synchronously like this is a bit non-idiomatic (are you sure you don't want refs?) which costs you some complexity, but it can be done.

17:54 drewr: In my use case, :a is a long-running thread which fires b's off periodically. What happens is b agents are return immediately, but their actions aren't fired until what seems like too late.

17:55 Chouser: 'sends' done in an agent's action are held until the action is complete. this is a feature.

17:56 agent :a is in some kind of loop, but not sending to itself?

17:57 drewr: Yes, :a is doing something similar to (loop [] (something-that-eventually-fires-b) (Thread/sleep ...) (recur)).

17:58 Chouser: it might help to (send *agent* thisfn) instead of recur. That will allow other sends to go as well.

17:59 drewr: You mean recurse by creating another agent?

17:59 hiredman: this might also be faq worthy

17:59 Chouser: drewr: no, recurse by sending to your own agent again

18:00 hiredman: *agent* is bound to the current agent inside an agent action

18:00 Chouser: drewr: this is how at least one of the agents behaves in Rich's ant demo

18:00 drewr: Ah. Hm, let me look at that.

18:02 hiredman: man, I miss clojurebot

18:02 it's like phantom limb

18:02 drewr: OK, (send-off *agent* #'behave).

18:04 hiredman: clojurebot: FAQ#2 is sends and send-offs that occur in an action sent to an agent do not take place until the agent's state changes

18:05 Chouser: drewr: right, though there's no need for the #' prefix anymore

18:06 Chousuke: hiredman: talking to ghosts now? where is clojurebot, anyway?

18:06 hiredman: hard drive died, so I need to rebuild the machine

18:06 Chousuke: ah.

18:06 drewr: Chouser: So send* won't consume the stack?

18:07 It will just fire off new threads and the old ones gc?

18:07 Chouser: (send (agent 9) (fn act [v] (prn v) (when (pos? v) (send *agent* act) (dec v))))

18:07 hiredman: cute

18:08 Chouser: drewr: even better, it will probably return the current thread to the pool before the new one is needed, so it may even use the same thread.

18:08 but yes, no consumption of finite resources

18:10 interesting -- using 'send' on this dual-core laptop, the action is indeed run on the same thread each time.

18:10 drewr: Sweet.

18:11 Chouser: using 'send-off' it oscilates between two threads.

18:11 I wouldn't bet too heavily on either behavior in any given circumstance, of course.

18:12 drewr: so that'll get your sends to agent :b going periodically. you still need the top-level thread to wait until they're all done?

18:13 drewr: In this case, :b is a network connection, and :a watches to see if any die and restarts them.

18:14 Starting works great, but the restarts involve the nested agent issue.

18:14 Chouser: sure.

18:14 drewr: Each connection has a listener agent which is another long-running loop that's doing (read-line) on the input stream.

18:15 These listener agents (and their associated async msg queues) don't ever have their actions fired.

18:15 Presumably that's because of my infintely loop-recurs that don't return.

18:16 Chouser: right. another benefit of the re-send looping is you can swap in a new definition of your function at runtime and the next send will pick it up.

18:16 drewr: Ah, yes.

18:24 So in (send *agent* foo), does the arg to foo become the future state of the first run through foo?

18:25 Chouser: no, the return value of the action becomes the new state of the agent.

18:25 in that little example I posted above, I did the (dec v) after the (send ...)

18:26 drewr: That's what I was basing that on. I think you said what I meant by my question.

18:26 Just didn't express it clearly.

18:26 Chouser: :-) ok

18:54 arohner: I'm trying to read out of a socket, and BufferedReader.read() wants a buffer to fill up. What is the easiest way to create a buffer from clojure?

18:56 Chouser: you want the classic char[] variety?

18:56 arohner: ah, make-array

18:56 Chouser: yes

18:56 Chouser: right, (make-array Character/TYPE 1024)

18:57 arohner: thanks

21:28 (java.util.regex.Pattern/matches "(.+): (.+)" "Host: localhost:1344")

21:28 true

21:29 user> (. #"(.+): (.+)" (split "Host: localhost:1344"))

21:29 #<String[] [Ljava.lang.String;@19ad02>

21:29 user> (alength (. #"(.+): (.+)" (split "Host: localhost:1344")))

21:29 0

21:29 That is *completely* unhelpful

21:29 matches with zero length?

21:35 Chouser: (re-seq #"(.+): (.+)" "Host: localhost:1344")

21:36 the regex matches the entire string, so it's a match and you get an array

21:36 but the contents of the array are the pieces of the string separated by what matched -- which is nothing.

21:39 arohner: oh, I needed to use re-matches

22:07 pjb3: Hey, I have a solution for Paul Graham

22:07 's Accumulator Generator in Clojure: http://github.com/pjb3/accgen/tree/master/accgen.clj

22:07 This seems pretty good, any ideas on how to do it differently?

22:08 hiredman: lisppaste8: url?

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

22:10 hiredman: pjb3: http://paste.lisp.org/display/70873

22:11 pjb3: hiredman: huh?

22:11 hiredman: its a counter

22:12 pjb3: The problem: Write a function foo that takes a number n and returns a function that takes a number i, and returns n incremented by i.

22:12 hiredman: so how c works is

22:12 (c 3) returns a function

22:13 which returns a function, etc

22:13 until you pass the function something not a number

22:13 at which point it tells you how many times you called the function

22:13 pjb3: hiredman: well, that's nice, but I don't see how that's a solution to the problem

22:14 hiredman: it is a subset of the problem, the case where you increment by 1

22:15 anyway

22:16 pjb3: hiredman: It's a solution to a different problem

22:16 hiredman: I did not read the problem, I just saw "Accumulator Generator"

22:16 pjb3: (let [acc (foo 1)] (acc 20) (acc 21))

22:16 should be 42

22:17 I think the original intent of the problem is basically a test to see "does your language have closures and lambas"

22:17 Which PG considers to be important things

22:18 but the other thing you need is mutable state

22:19 This works pretty much the same way, except you have to give the function access to the atom as a closure

22:33 doublefree: Hi all, I'm new to Clojure, and I wonder what is a fast way to select a (or n) random element(s) from a potentially large set?

22:35 I'd like to avoid converting the set to a vector if possible

22:40 pjb3: doublefree: Off the top of my head, I don't know of a way to do that without converting it to a vector

22:42 doublefree: pjb3: ok - perhaps it is my data's destiny to live in a vector after all

22:42 pjb3: doublefree: Does this help? http://stackoverflow.com/questions/124671/picking-a-random-element-from-a-set

22:47 doublefree: I see the proposed Lisp solution there reflects my initial approach (the following doesn't work because PersistentHashSet does not support nth which makes sense I suppose): (defn pick-random [set] (nth set (random (count set))))

22:47 pjb3: huh, sets aren't seqs?

22:48 doublefree: Yeah, I was just trying that, but ran into sets not being a seq

22:49 hiredman: nothing is it's own seq except lists

22:49 but seq knows how to turn sets into seqs

22:49 user=> (seq #{:a :b :C})

22:49 (:b :a :C)

22:50 pjb3: (defn pick-random [set] (let [sq (seq set)] (nth sq (rand-int (count sq)))))

22:53 doublefree: pjb3: thanks works well enough for now!

22:53 pjb3: doublefree: yeah, not sure if that's "fast"

22:53 is (seq #{...}) O(n)?

22:54 Or is there some fast way under the covers of making a lazy-seq from a set

22:55 clojurebot: ?

22:56 hiredman: I have the new hard drives for the clojurebot machine

22:56 so it will be back soon

22:56 pjb3: anyway, the docs for nth say it takes a coll, and the docs for sets says it is a collection

22:57 Right, and (coll? #{}) is true

22:57 so, that's a little confusing

22:59 hiredman: maybe something to mention to rhickey

23:08 Chouser: almost none of the collections are seqs, but all provide efficient (generally lazy) seqs when you pass them to seq

23:09 * drewr is especially confused about send and send-off now

23:09 Chouser: nth doesn't work on all collections, and unlike some functions doesn't apply seq to its parameter

23:09 hiredman: yeah I just looking at the source in google code

23:09 drewr: I changed some sends I had to send-off and certain things started working and I have no idea why.

23:10 hiredman: maybe it should say "only works on certain collections"

23:10 I take that back

23:10 the doc string doesn't say it takes collections

23:10 don't know why I thought it did

23:11 Chouser: it uses 'coll' as the arg name

23:11 hiredman: short for collar of course

23:47 doublefree: I find it strange that (first #{1 2}) and (second #{1 2}) work while (nth #{1 2} 0) does not... I see first and second call seq on their args, and apparently nth does not. I wonder why this is.

23:47 Chouser: nth can't be any faster that O(n) on a seq

23:47 but it it works in O(1) time on vectors, array, etc.

23:53 doublefree: yes, but nth could seq its arg if it's not of a class that provides constant time lookup itself and in doing so provide a more consistent interface. anyways no biggy.

Logging service provided by n01se.net