#clojure logs

2009-05-28

00:16djpowellah k
00:49DekuDekuplexHi, I'm having difficulty in posting a message to the Clojure Google group.
00:51DekuDekuplexEvery time I post a message, it doesn't appear. Is there some kind of limit to the number of BCC's?
00:52cadsthis is freaky, I'm starting to be able to unconsciously type the correct number of closing parens to a statement, even if it's not clojure
00:53cadsit's wierd, I won't know how many parens I put down but if I count them it's correct
00:53DekuDekuplexDoes anybody know how to reach Rich Hickey or the Google group admin? I can't get my message to post.
00:54cadswhat's a BCC?
00:55DekuDekuplexBlind Carbon Copy. Similar to CC, for Carbon Copy, except it's invisible to any of the recipients.
00:55DekuDekuplexUsed to send copies of outgoing mail to other accounts of my own.
00:55jdzand besides being invisible it in no way interoperates with the mail sending, i.e. bcc is not your problem.
00:56DekuDekuplexNot necessarily. I heard that some servers have a hard limit on the number of recipients (typically 5), including BCC's.
00:56DekuDekuplexI suspect that the Clojure group has a limit of <=4 for the total number of recipients who may be included on a posted message.
00:57jdzwhy are there more than 2 recipients of that message is if is being sent to a group?
00:57DekuDekuplexIf so, then I won't be able to post, because I need to send copies to 4 of my own accounts, plus the recipient, for a total of 5 minimu.
00:57DekuDekuplexs/minimu/minimum
00:58DekuDekuplexThe reason is that I want to have backup copies of my send messages besides one in "Sent Items" in my other accounts.
00:58DekuDekuplexs/send/sent
00:58DekuDekuplexE.g., copies in Yahoo! Mail, Google Mail, etc.
00:58DekuDekuplexOne copy for each e-mail account of my own.
00:59jdztalk about paranoia
00:59DekuDekuplexI have 4 e-mail accounts, so I send out 4 BCC'd copies of each message I send.
00:59DekuDekuplexI can lose up to three accounts, but still retain copies of all my sent messages.
00:59jdzyeah, that's what paranoic about it
01:00DekuDekuplexUseful in a nuclear war, for example.
01:00jdzhow?
01:00DekuDekuplexLess possibility of all the servers losing all their backup data.
01:00jdzwell, and you are sure you will want to read your sent messages to clojure google group after the bombs go flying?
01:01eevar2DekuDekuplex: I imagine you might be subject to moderation until your first message has been approved
01:01DekuDekuplexMaybe not bombs, but could be a hurricane, an earthquake, etc. Never know.
01:01eevar2farily common google group setting to avoid spammers
01:01DekuDekuplexThat's another thought, but it's been over 3 hours, and it still hasn't posted.
01:01DekuDekuplexJust a technical question about a Clojure program.
01:02DekuDekuplexHm.
01:02DekuDekuplexMaybe I can ask the question here.
01:02jdznow i want to see this message which in no way can be let to be lost :)
01:03DekuDekuplexOn slide 20 of the talk "Clojure: A Dynamic Programming Language for
01:03DekuDekuplexthe JVM" (see
01:03DekuDekuplexftp://lispnyc.org/meeting-assets/2007-11-13_clojure/clojuretalk.pdf),
01:03DekuDekuplexby Rich Hickey, the following function and evaluation results are
01:03DekuDekuplexdefined:
01:03DekuDekuplex>(defn argcount
01:03DekuDekuplex> ([] 0)
01:03DekuDekuplex> ([x] 1)
01:03DekuDekuplex> ([x y] 2)
01:03DekuDekuplex> ([x y & more]
01:03DekuDekuplex> (+ (thisfn x y) (count more))))
01:03DekuDekuplex>
01:03DekuDekuplex>(argcount 1 2 3 4 5)
01:03DekuDekuplex>-> 5
01:03jdzuse paste please
01:03DekuDekuplexHowever, when I evaluate this function in the REPL, the following
01:03DekuDekuplexerror is returned:
01:03DekuDekuplex>java.lang.Exception: Unable to resolve symbol: thisfn in this context (NO_SOURCE_FILE:6)
01:03DekuDekuplex> [Thrown class clojure.lang.Compiler$CompilerException]
01:03DekuDekuplexHowever, no definition is given for "thisfn" in the talk.
01:03DekuDekuplexForgive me if I am missing something very obvious, but does anybody
01:03DekuDekuplexknow where I can find the definition of "thisfn"?
01:03DekuDekuplexThat's a copy of the message.
01:03tWipthisfn is no more
01:04DekuDekuplexHow do I use paste?
01:04jdzlisppaste8: url
01:04lisppaste8To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste.
01:04DekuDekuplexOk, let me try it then.
01:05jdzand replace the thisfn with argcount
01:06jdzDekuDekuplex: and i hope you have noticed that it's year 2009 now and that clojure has a version 1.0 release, and much has changed since the date of that .pdf?
01:07DekuDekuplexHm ... I was looking for a good tutorial for functional programmers, but all I could find was one with a lot of examples and not much theory, and a for-fee book.
01:07jdzmaybe time flies by faster when you think about bomb shelters half of the time...
01:07DekuDekuplexThen I came across those slides.
01:07DekuDekuplexlol ;)
01:07jdzjust get clojure-contrib and you'll find loads of code to read
01:08DekuDekuplexEr ... I was looking for something similar to the book Programming in Haskell, but for Clojure students.
01:08jdzyou'll have to wait for the clojure book to come out, then
01:08jdzor get the pdf version
01:09DekuDekuplexThats a for-fee book, IIRC?
01:09lisppaste8DekuDekuplex pasted "a question about the definition of the variable arity function in "Clojure: A Dynamic Programming Language for the JVM," by Rich Hickey" at http://paste.lisp.org/display/80963
01:10jdzDekuDekuplex: what's wrong for asking fee for one's work
01:10jdz?
01:10DekuDekuplexAh, finally I got it to paste. Just pasted the earlier post.
01:10DekuDekuplexI'm broke this month.
01:10DekuDekuplexUntil my next paycheck on June 20.
01:10DekuDekuplexAlso, I live in Tokyo, where costs are very expensive.
01:11DekuDekuplexNo credit card right now, either.
01:11jdzand, btw, i already told you the solution to your problem...
01:11DekuDekuplexYes, use argcount instead of thisfn, right?
01:13jdzreading actual real-world code is the best way to learn a programming language.
01:14DekuDekuplexThat's useful if you want to write an actual application. If all that is wanted is to compare semantics from a PLT perspective, then a theory book is more useful, though.
01:15jdzPLT?
01:15DekuDekuplexProgramming Language Theory
01:15DekuDekuplexI used to study formal semantics in college. Interested in the lambda calculus.
01:15jdzyou can't get PLT semantics out of tutorial code, you know that, right?
01:16jdzat least not more than from code that actually does something interesting
01:16DekuDekuplexRight, but I started out comparing how to write Towers of Hanoi in Haskell, Scheme, and Clojure, and was looking for a way to move on to other topics along that line.
01:17DekuDekuplexClojure is very interesting, because it looks like a combination of Lisp and Java.
01:17jdznot really, not to me at least.
01:17jdzthere is not much Java in clojure language
01:18jdz(the little that is are the Java interop things)
01:18DekuDekuplexHm. I was especially surprised that (cond ...) statements didn't require parentheses for each condition.
01:18DekuDekuplexThey do in Scheme and Common Lisp.
01:18DekuDekuplexIt was much easier to write Towers of Hanoi in Clojure than in Common Lisp, so I wanted to pursue Clojure further.
01:19DekuDekuplexThe problem with Scheme is that each implementation has some kind of problem.
01:19jdzwhat was easier?
01:19DekuDekuplexEasier to figure out how to write.
01:19jdzi mean compared to Common Lisp?
01:19DekuDekuplexYes, definitely.
01:19jdzyou mean it's easier to write 10 lines of clojure code than Common Lisp code?
01:20DekuDekuplexFor that particular algorithm, yes.
01:20DekuDekuplexEasy to figure out from the examples.
01:21DekuDekuplexI got stuck in Common Lisp when the "(progn ...)" statement behaved differently from the "(begin ...)" statement in Scheme with respect to recursive calls of "(format ...)."
01:22DekuDekuplexBut then "(do ...)" in Clojure pretty much behaved as I expected, so writing Hanoi was a breeze.
01:22jdzi can't imagine how that would look like
01:22DekuDekuplexWhich part?
01:22jdzthe recursive calls to format in progn
01:23DekuDekuplexWell, let me paste some code that I have written for Hanoi in Scheme and what I tried to write in Common Lisp, and what I wrote in Clojure.
01:23DekuDekuplexOne second....
01:25lisppaste8DekuDekuplex annotated #80963 "PLT-Scheme-specific Version 1.1.1 of Towers of Hanoi" at http://paste.lisp.org/display/80963#1
01:25DekuDekuplexThat was my Scheme version of Towers of Hanoi.
01:26jdzthere is no (begin ...)
01:27DekuDekuplexIn particular, the part after the "(else ...)" recursively calls "(hanoi-helper ...)", and the "(printf ...)" statements are all correctly displayed.
01:27jdzok, and the CL version?
01:27DekuDekuplexRight, but I can also use "begin" for the middle part.
01:27jdzand clojure please
01:27DekuDekuplexOk.
01:27DekuDekuplexOne moment....
01:29lisppaste8DekuDekuplex annotated #80963 "PLT-Scheme-specific Version 1.1.1 of Towers of Hanoi" at http://paste.lisp.org/display/80963#2
01:30DekuDekuplexThat's my (non-working) CL version.
01:30DekuDekuplex(hanoi 1) works, but not (hanoi 2).
01:31DekuDekuplexOnly the final "(format ...)" statement is actually executed.
01:31DekuDekuplexThat's where I got stuck.
01:31DekuDekuplexThen I got frustrated, and tried Clojure.
01:31DekuDekuplexNow for the Clojure version....
01:32lisppaste8DekuDekuplex annotated #80963 "Clojure version of Towers of Hanoi" at http://paste.lisp.org/display/80963#3
01:33ChousukeDekuDekuplex: defn inside defn is not good style.
01:33DekuDekuplexRecursive calls to "(hanoi-helper ...)" correctly invoke multiple calls to "(format ...)".
01:33Chousukedefn always makes global functions; if you want locals, use (let foo [(fn ...)])
01:33DekuDekuplexI wanted to use "(lambda ...)", but there is no lambda in Clojure.
01:33Chousukeit's called fn
01:33DekuDekuplexAh, I get it.
01:34Chousukethere's also a quick syntax for them: #(foo % %1 %2 %&)
01:34DekuDekuplexSo replace "(defn hanoi-helper [n source dest using] ...)" with "(let hanoi-helper [n source dest using] ...)"?
01:35Chousukewhere % == %1, and %n means (nth parameter), and %& is the "rest parameter"
01:35djpowell`it would be (let [hanoi-helper (fn [n source dest using] ... )] ...)
01:35Chousukeoops. intended quotes instead of parens ther e:P
01:35djpowell`i think
01:35Chousukeyeah
01:36Chousukeand if it needs to call itself recursively, you need to do (let [hh (fn hh [params] ... (hh))] or use recur
01:36DekuDekuplexSo "(let "hanoi-helper (fn [n source dest using] ...)" ...)"?
01:37DekuDekuplexSingle-quotes?
01:37Chousukea vector
01:37DekuDekuplexBrackets?
01:37Chousuke,(let [x 1 y 2] (+ x y))
01:37clojurebot3
01:38djpowelllet takes square brackets around its args which are pairs of varname/values
01:38DekuDekuplexOk.
01:38djpowellit is a convention in clojure for other let-ish things to do that too
01:39jdzDekuDekuplex: i suggest you go read documentation of CL's format function before spreading more uninformed assertions.
01:40DekuDekuplexSo "(let [hanoi-helper (fn [n source dest using]) ...] ...)"?
01:40Chousukeyeah
01:41DekuDekuplexOk, let me rewrite that earlier Clojure function using that syntax. One minute, and I will post it....
01:41Chousukethough as I said, if hanoi-helper calls itself recursively, you need to give it a name after the "fn" part too; it can't see the name in the let
01:42Chousuke,(let [v [1 2]] (let [[x y] v] (+ x y))); let can also do this. note how the structure of the items matches.
01:42clojurebot3
01:42jdzand a general observation: comparing programming languages one does not know from PLT perspective (well, any perspective) is useless
01:43lisppaste8DekuDekuplex annotated #80963 "Revised Clojure Towers of Hanoi function" at http://paste.lisp.org/display/80963#4
01:43DekuDekuplexI haven't tested this one yet. Let me test it.
01:44DekuDekuplexjava.lang.Exception: Unable to resolve symbol: hanoi-helper in this context (NO_SOURCE_FILE:6)
01:44DekuDekuplex [Thrown class clojure.lang.Compiler$CompilerException]
01:44DekuDekuplexNope.
01:44DekuDekuplexAh, need to give it a name.
01:44DekuDekuplexOk....
01:45jdzDekuDekuplex: make sure you back up this IRC session in at least 4 places so you can read it once a day for following weeks
01:45jdzmaybe you'll learn something
01:45DekuDekuplexI'm already backing it up.
01:45DekuDekuplexJust saved it.
01:46DekuDekuplexCan I give it the same name after "let" and after "fn"?
01:48lisppaste8rhickey annotated #80963 "hanoi using letfn" at http://paste.lisp.org/display/80963#5
01:48lisppaste8DekuDekuplex annotated #80963 "This Clojure code didn't work...." at http://paste.lisp.org/display/80963#6
01:49DekuDekuplexletfn! Interesting!
01:49opqdonutis there a nice way to concat two vectors and keep the result a vector
01:49opqdonutshort of something like (comp vec concat)
01:50rhickeyopqdonut: (into v1 v2)
01:50rhickey,(into [1 2 3] [4 5 6])
01:50clojurebot[1 2 3 4 5 6]
01:50opqdonutah, great!
01:51DekuDekuplexYes! That worked!
01:52DekuDekuplexUse letfn instead of fn for a recursive call. So letfn is like a lambda closure?
01:52jdzDekuDekuplex: now go change the first parameter of format call from nil to t and reflect on any insights you get. please.
01:53DekuDekuplexIn my CL code?
01:53rhickeyletfn is like Scheme letrec or CL labels, limited to fns only
01:53jdzDekuDekuplex: yes, your CL code.
01:53DekuDekuplexAh, letrec. Ok.
01:53DekuDekuplexRecursive version of let.
01:55DekuDekuplexOk, (was answering a question from someone just now), let me change it now.
01:55rhickeyyou could also have done (let [hh (fn hh [args] ... (hh ...))] (hh ...))
01:59DekuDekuplexI just changed the CL function and tried it, and this time it returns nil.
01:59DekuDekuplexs/nil/NIL
02:00DekuDekuplexHm ... let me look up some documentation for the format function....
02:02DekuDekuplext is supposed to be for standard output, according to http://www.gigamonkeys.com/book/a-few-format-recipes.html.
02:03DekuDekuplexBut all it does is returns NIL. Hm....
02:05DekuDekuplexSomehow I get the feeling that this problem isn't about format, but about how to get CL to allow multiple side-effects in a sequence of recursive calls.
02:05jdznope
02:05DekuDekuplexIt's about format?
02:05jdzif you'd translate the code directly, you'd also put a newline after the output
02:08DekuDekuplexAs in "\n"?
02:08hiredmanDekuDekuplex: clojure.core/format is more like java's Format then CL's
02:08jdzthat won't work in CL
02:08DekuDekuplexHow about "(newline)"?
02:08jdztry ~%
02:09jdzor just (terpri) after format
02:09DekuDekuplexStill same result.
02:09DekuDekuplexJust NIL.
02:10jdzwell, at this point i somehow don't trust any of your observations...
02:10DekuDekuplexThat line reads "(cond ((equalp n 1) (format t "Move disc from ~A to ~A.~%" source dest))".
02:11DekuDekuplexLet me paste the entire CL program.
02:11jdzDekuDekuplex: depending on your implementation, you might want to add a call to finish-output after format
02:12lisppaste8DekuDekuplex annotated #80963 "broken CL Towers of Hanoi program and result" at http://paste.lisp.org/display/80963#7
02:13jdzthat version works like charm for me on SBCL
02:13DekuDekuplexI'm using GNU CLISP.
02:13jdzwell, try calling (finish-output) after the (hanoi 3) call
02:14jdzi never liked clisp myself
02:15lisppaste8DekuDekuplex annotated #80963 "finish-output didn't work...." at http://paste.lisp.org/display/80963#8
02:15DekuDekuplexNope, that didn't seem to work, either. Just pasted the result.
02:16DekuDekuplexI can guess why.... ;)
02:16jdzwell, i've said enough on this offtopic
02:16DekuDekuplexNow you see why I like Clojure more than CLISP in this case.
02:17jdzCLISP != Common Lisp
02:17rsynnottDekuDekuplex: #lisp, perhaps?
02:17DekuDekuplexIndeed.
02:17rsynnottDekuDekuplex: you muight want force-output
02:17jdzand not liking things because you don't understand them is not very productive
02:17cadshey, I've looked at some common lisp code recently, and reading it I got the feeling of old and dusty punchcards, and when I translated it to clojure it felt a lot crisper for some reason... is this just my subjective experience, as in would a clisper feel the same way about clojure not being traditional?
02:17DekuDekuplexWell, I used to use CLISP in college, too, and had similar problems back then, too.
02:18DekuDekuplexProbably.
02:18rsynnott(also, clisp the implementation is not representative of modern cl impls)
02:18DekuDekuplexIt's hard to get SBCL to work with SLIME on Windows XP.
02:19cadsI was referring to popular, common lisp, not necessary gnu clisp
02:19DekuDekuplex(force-output) after (hanoi 3) had the same result....
02:19DekuDekuplexWhich implementation for Windows XP and SLIME?
02:20jdzthe problem is not the output functions of specific common lisp implementations, it's about jumping to wrong conclusions. (this all started with my curiosity about recursive calls to format in progn...)
02:21DekuDekuplexAs in what the cause of the problem was: format vs. side-effects?
02:21jdzno. there has never been any issue with progn/format interaction
02:22DekuDekuplexHm. Because when I type very similar code in PLT Scheme, it works fine.
02:22jdzas opposed to what you stated at the beginning
02:22DekuDekuplexSame for Clojure.
02:22DekuDekuplexBut not CL, for some reason. Strange....
02:22jdzthat's the problem. you write similar code in different programming languages and expect your code to be perfectly correct in those languages.
02:23jdzyou can't compare apples to oranges thinking that they are all bananas
02:23DekuDekuplexInteresting analogy.
02:23rsynnottDekuDekuplex: ideally, do not use common lisp on win32
02:23rsynnotthowever, ccl works okay these days
02:24DekuDekuplexNo kidding. The problem is, I only have time to study at the office during brief respites, and no time at home, so I'm stuck with win32.
02:25DekuDekuplexCan't really install Linux on an office computer.
02:25DekuDekuplexI do have a Mac at home, but no time to use it.
02:25rsynnottccl, then
02:25jdzDekuDekuplex: then go download LispWorks and you'll have much better experience.
02:25DekuDekuplexLispWorks ... hadn't thought about that.
02:25DekuDekuplexI thought it'd be the same, because it's also Common Lisp.
02:26DekuDekuplexI heard there was a free version that doesn't allow saving stand-alone executables.
02:26jdzwell, if there were no differences between implementations, why do you think there are more than one?
02:27DekuDekuplexI thought the differences would be minor, as in SWI-Prolog vs. GNU Prolog.
02:27jdzbased on what?
02:27DekuDekuplexWell, I've tried several different implementations of Scheme, for instance, but they all work similarly.
02:28DekuDekuplexPLT, MIT/GNU, Gauche, etc.
02:28DekuDekuplexSo I thought it was similar for Common Lisp.
02:28jdzyou thought wrong. just accept it and move on.
02:28jdzi'll just shut up.
02:29DekuDekuplexHey, no need to get so drastic! I'll give LispWorks a try.
02:29eevar2DekuDekuplex: /join #lisp
02:30DekuDekuplexThe other problem with Common Lisp is that it's hard to ask anything on comp.lang.lisp without somebody coming out and making fun of the question.
02:30DekuDekuplexThere are certain ... denizens ... who inhabit comp.lang.lisp, who have a funny sense of etiquette.
02:31DekuDekuplexI'm used to USENET, but it's hard to find an alternative newsgroup.
02:31DekuDekuplexOk.
02:31DekuDekuplexI'll go try #lisp, too. Maybe my mileage will vary....
02:32DekuDekuplexI hope they aren't the same people who inhabit comp.lang.lisp.
02:32DekuDekuplexA few weeks ago, I tried creating a newLISP newsgroup by getting support on comp.lang.lisp, and a lot of the people there just made fun of newLISP.
02:33DekuDekuplexAre they the same people?
02:33rsynnottDekuDekuplex: in fairness, newlisp deserves to be made fun of
02:34rsynnottbut as long as you're polite #lisp is fine these days
02:34alinphi
02:34DekuDekuplexWell, now that I know it better, I can see that it has a lot of problems, but they compared it to "jack****."
02:34DekuDekuplex(I can't use that term here.)
02:34alinpdoes clojure have a special tuple data structure ?
02:34alinpor a sequence can be considered a tuple ?
02:35hiredmanalinp: most people use vectors as a sort of tuple
02:35DekuDekuplexOk, gotta go now. Thanks for the help. Session saved. Will go look at #lisp.
02:35DekuDekuplexBye.
02:35jdzwell, depends on what you mean by "tuple"
02:35hiredmanhandy because you don't have to worry about quoting
02:35alinpsomething like erlang's tuple
02:35jdzif it's something with first and rest, then yes, sequences are the tuples
02:35alinpin fact, I have other q
02:36alinpin erlang tuples are used within pattern matching; can we speak about pattern matching in clojure ?
02:37hiredmandoesn't have it, so speaking about it would be silly
02:37alinp:) ok
02:37hiredmanbut you can sort of do stuff like http://www.thelastcitadel.com/blag/clojure_multi-method
02:37alinpyes, I heard about it
02:37alinpthanks
02:38alinpbtw, that multi-method is pretty neat
02:47alinpjava.lang.Exception: The syntax for defmulti has changed. Example: (defmulti name dispatch-fn :default dispatch-value) (test_defmulti.clj:1)
02:47alinprunning the example that hiredman gave
02:47alinp(http://www.thelastcitadel.com/blag/clojure_multi-method)
02:51hiredmanyeah
02:51hiredmanthat code is like six months old
02:52hiredman(defmult fib identity :default :default)
02:52hiredmandefmulti
02:52alinpyes, this is how I made it
02:52alinpso it seems that is ok :D
02:53alinpwasn't sure that :default :default is not a nonsense
02:53alinp:)
03:05rhickeythe default is :default, so you can just leave that out
03:07hiredmanoh
03:08hiredmanwell thats nice
03:12hoeck,(count (apply concat (repeat 10000 nil)))
03:12clojurebot0
03:12hoeck,(count (apply concat (repeat 30000 nil)))
03:12clojurebotjava.lang.StackOverflowError
03:12hoeckis this a bug in concat?
03:12rsynnottpoor machine
03:12rsynnottyou are in effect trying to pass a function 30,000 parameters
03:13rsynnottsome sort of reduce type thing might be more appropriate in the circumstances
03:13hoeckor must i expect the stack-consuming behavior of concat?
03:13hoeckrsynnott: its the same when using reduce
03:14hoeck,(count (reduce concat (repeat 30000 nil)))
03:14clojurebotjava.lang.StackOverflowError
03:20rhickeyhoeck: in the enhancements I made for chunked seqs I made lazy-seq smarter about nested seqs - what's happeining with concat a bunch of nils is a long chain of lazy-seqs is created, evaluating the first of which recursively calls the rest
03:20rhickey,(count (reduce concat (repeat 30000 [1])))
03:20clojurebotjava.lang.StackOverflowError
03:21rhickeyhere:
03:21rhickeyuser=> (count (apply concat (repeat 300000 [1])))
03:21rhickey300000
03:21rhickey(it's good to be here :)
03:22hoeckrhickey: so the problem is solved on you machine with the chunked-seqs implementation?
03:23rhickeyyes, not really relying on the chunked seqs, just an enhancement to lazy-seq
03:24rhickeyI'll try to move the chunked work onto trunk - kind of frustrated with having it be in a git repo I can work on on only one machine
03:24hiredmanerm
03:25Chousukewhat's preventing you from cloning the repo somewhere else?
03:25hiredman?
03:25rhickeywith git svn there are caveats about using it as you would normally in git, since changes can't get synched back correctly
03:26Chousukethe new clone is "pure git", but you can push its changes back to the svn-git repo and dcommit from there
03:26rhickeysee caveats here: http://www.kernel.org/pub/software/scm/git/docs/git-svn.html
03:27rhickeyI'm not going to start sending myself patches when I switch machines
03:28rhickeyand if I can only synch properly by dcommitting I might as well work on trunk
03:29hoeckrhickey: okay, good to know its fixed, it took me about 4 hours to find the cause of the stackoverflow in my code
03:29Chousukerhickey: hmm :/
03:30ChousukeSVN really complicates working with git ;(
03:31rhickeyChousuke: apparently. I wanted to try it, but overall I don't think it is really giving me the full git experience
03:32rhickeyjust left me uncomfortable with a chunk of my work stuck on one machine and not on a server
03:49Chouserinotify calls its handlers "watches", as in "add_watch", "remove_watch"
04:36rhickeyalready did that
04:36rhickeyit's up
04:37Chouseryes, I meant since you did a dcommit, I did a rebase.
04:37rhickeyah
05:06cemerickrhickey: do you have a high-level writeup of chunked seqs and/or the instance stuff somewhere (like what you did with clojure.org/lazier for some period)?
05:07rhickeycemerick: not yet, I will, but they are not exposed in the api yet in svn
05:10cemerickFrom what I've gleaned from irc logs, instance looks particularly interesting to me. Perhaps something that can replace my genbean contraption.
05:10Chouserinstance will be very cool
05:11rhickeyyes, instance is a key to less Java in Clojure impl
05:12cemerickI should post a revised genbean. Looking back at my original postings, that first code was positively *fugly*.
05:21Chousukehmm.
05:22jdzis there any var that would tell me if code is being compiled?
05:23jdzi want to execute some code when a namespace is being loaded, but not when it is being compiled
05:24jdz(it is related to loading C library)
05:25cemerickjdz: I think *compile-path* is always set when one is compiling
05:25Chouser,*compile-files*
05:25clojurebotfalse
05:25cemerick(or, at least, java.lang.Compile always sets it -- I never compile from the REPL)
05:25Chousukehm
05:26Chouserjdz: You want to check *compile-files*. *compile-path* defaults to "classes" even when you're not compiling.
05:26Chousukeit's also used only four times in the core code :P
05:27jdzChouser: yes, *compile-files* is exactly what i need
05:27Chousukeall others use :inline metadata directly it seems.
05:28cemerickjdz: sorry for the bad pointer :-/
05:30jdzworks like charm
05:41jdzbtw, i was looking in the http://clojure.org/compilation for the name if this variable, and it is not mentioned there...
05:43lisppaste8rhickey pasted "play along w/chunked seqs" at http://paste.lisp.org/display/80967
05:46jdzoh, too bad the times are not included in the comments
05:46rhickeyvector seqs are now chunked, showing transparent interop with chunk ignorant code
05:47rhickeystill need names for the buffer, chunk and chunked first/rest/next stuff
05:48rhickeyjdz: summary - chunked seqs rule
05:48jdzwell, that i can gather from your excitement :)
05:49rhickeythe map*/reduce*/filter* will go away, chunked seqs will be tested for in normal map/reduce/filter
05:49Chouseryou'll want a chunked-cons too?
05:50rhickeyChouser: yes
05:51Chouserthese new names will show up only in code that's already expending extra effort to perform well
05:51Chouserso if they're a little long it's not too big a deal, right?
05:51Chouseralthough chunked-cons, chunked-rest, etc. seem awfully verbose
05:52jdzrhickey: why do you need separate functions for first/rest/next?
05:52Chouserjdz: chunked-rest means the next *chunk*, not the next item.
05:52Chouserbah, not quite
05:52rhickeyjdz: because they do different things, chunked seqs still support first and it returns 1 item, rest returns other than the first item etc
05:52jdzyes, but if the sequence is chunked, you'd get next chunked-cons
05:53Chouserjdz: chunked-first means the first *chunk*, not the the first item.
05:53jdzimplementtion details
05:53rhickeyjdz: just because the seq you have is chunked doesn't mean it's rest/next is also
05:53jdzimplementation
05:53rhickeyjdz: not at all
05:53rhickeyfirst and chunked-first return 2 different things
05:54rhickeya chunked seq is not a seq of chunks
05:54Chouserchunked-first fails on a non-chunked seq?
05:54jdzyes, that's clear
05:54jdzbut for me as a user, it does not matter if the sequence is chunked or not
05:55jdzfor me first would return first item from the seqence, never mind the minor detail that next chunk was pulled off of it
05:55Chouserjdz: right, you can ignore the chunkiness and write correct code that may or may not be faster than it used to be.
05:55rhickeybut there are still 2 functions that do different things and need different names
05:56jdzwell, yes. for those who want to take advantage of chunkiness. got it.
05:56{newbie}Hi is it idiomatic to use struct-maps as union types?
05:57rhickeyChouser: I'm wary of making them too long
05:57Chouser{newbie}: leaving various subsets of the values as nil?
05:57rhickeyChouser: yes, chunked-first/rest/next require chunked seqs, the presumption being all correct code will be testing for chunked or downstream logic for code that tests
05:58Chouserrhickey: ok
05:58mattreplchunked sequence would allow for, say, building sequences from paginated data? e.g., grabbing a page of results where each each result is an item in the sequence and each page is a chunk?
05:58{newbie}Chouser: no
05:58{newbie}Actually I have a much bigger problem
05:58{newbie}how do I organize a clojure problem
05:58{newbie}program*
05:59{newbie}I have some experience with ocaml
05:59{newbie}but without static stypic to guid the module coding
05:59{newbie}i'm a bit lost
05:59rhickeymattrepl: chunked seqs provide an advantage when the chunks can support indexed access
06:00rhickeyi.e. lists will never provide chunked seqs
06:00Chouser{newbie}: that's a very broad question. Have you looked on the google group? Various forms of that question come up from time to time.
06:01rhickeyanyway, before I move chunks into map/reduce/filter I want to see that everything is ok with vector seqs being chunked. Clojure itself, contrib and its tests seem ok
06:02JoelMcCrackenwhat is the best way to get the contents of a url into a string?
06:02{newbie}Chouser: thanks I think I found a thread on the subject
06:04hiredmanJoelMcCracken: http://gist.github.com/119375
06:05JoelMcCrackennice, that come up a lot or have you just had it around?
06:06hiredmanI had it around, and I have nice vim plugin that dumps selected text to gist
06:06JoelMcCrackenniiice
06:06ChouserI'm sure what hiredman has is much more correct, but this also works: (with-open [s (.openStream (java.net.URL. "http://google.com/&quot;))] (apply str (map char (take-while pos? (repeatedly #(.read s))))))
06:07JoelMcCrackenah, cool. thanks for that, too
06:09Chouserhm, I bet mine doesn't do unicode correctly.
06:10Chouserhiredman: any reason you're not using (apply str ...)?
06:10lisppaste8jdz pasted "stream slurping lying in my utility package" at http://paste.lisp.org/display/80970
06:10tashafawhen is the next clojure boston meeting?
06:10clojurebotclojure is like life: you make trade-offs
06:10jdzhere, no reading by single characters and applying str later
06:13jdzand besides, you cannot properly read unicode by trying to convert single bytes to characters
06:14cemerickooh, I didn't know there *was* a boston clojure meeting :-)
06:14hiredmanChouser: I think I was following some java code
06:14Chouserright, but using a LineReader like hiredman should handle unicode just fine.
06:15Chouserhiredman: ah, sure.
06:15jdzyes, *Reader should be fine
06:15Chousukereading a single byte at a time sounds slow though ;(
06:15ChouserDoes BufferedReader read a single byte at a time?
06:15jdzthat's why everybody should use the my awesome buffered reader :)
06:16ChousukeChouser: .read does, doesn't it? and if you map over that, there will be the function call overhead for every byte.
06:16jdzChouser: well, you get one character at a time, but OS reads are in chunks
06:16jdzthat's the whole purpose of buffered things
06:16ChousukeChouser: though I bet chunked seqs will help with this too :D
06:16ChouserChousuke: yes. please ignore my bad example. It is brief but incorrect and inefficient.
06:22replacaI've noticed that contrib has been *very* stable the last few weeks
06:44cemerickhave any enterprising git-svn users tried maintaining local patch sets against clojure's svn?
06:44Chouseryes
06:45ChouserI was maintaining clojurescript-required changes to clojure proper as a git branch for quite a while.
06:46cemerickChouser: I assume doing so works well, then? So far, we've just been roping in clojure jars as things go along, but now I'd like to start cherry-picking patches, etc.
06:46cemerickah, nice
06:46cemerickI've just never maintained a patch queue like that. Good to know it works nicely.
06:47danlarkinprobably best to use branches, have master be unadulterated svn mirror and then pull that into your changes branch
06:47danlarkinI guess(TM(TM)
06:47ChousukeI do that with every git repo I have.
06:47cemerickheh
06:48Chousukemaster always represents my view of the upstream; I never commit anything on it.
06:48Chousukethat is, unless I actually need to push stuff :P
06:48cemerickyeah, that's roughly what I had in mind, although I hadn't thought it through entirely.
06:49cemerickis there a form like -> that will just return nil if any of the exprs return values is nil?
06:49Chousuke-?> in contrib I think
06:51cemerickah, next to defnilsafe.
06:51cemerick-?> is hard to look at though ;-)
06:54Chousukeit makes me think of XML :P
06:54cemerickyeah. like a PI
07:11Chouserbother. jna.Structure appears to require the use of reflection to find a Class's list of fields and their types.
07:37danlarkinAnything clojure-related happening in Boston the weekend of June 26-28? I'll be in town
07:42{newbie}:| I'm afraid I am going to use closure as a glorified imutable gc'ed C
07:43{newbie}and functional
07:43gnuvinceSo you're going to use it TOTALLY unlike C is used?
07:43JoelMcCrackenclojure's macros don't seem very documented; are they similar to common lisp's
07:43JoelMcCracken?
07:43gnuvinceJoelMcCracken: yes
07:43JoelMcCrackenessentially the same?
07:44gnuvinceJoelMcCracken: pretty much, yes.
07:44hiredmanclojure's macros are functions
07:44Chouserhiredman: implementation detail
07:44hiredmanChouser: an excellent one
07:44ChouserJoelMcCracken: Clojure uses ~ and ~@ instead of , for inserting things into syntax-quoted forms.
07:45gnuvinceiirc, the only difference is the capture of variables.
07:45ChouserJoelMcCracken: and plain symbols in syntax-quote become fully-qualified to improve hygine.
07:45JoelMcCrackenis thie documented anywhere?
07:46viator_sgAnybody have tried to build clojure-android recently?
07:46dnolenalso popular Lisp implementations warn on undefined symbols in macros, Clojure will throw an exception.
07:48{newbie}does anyone have an ant script that just compiles the java classes but runs the clojure scripts in the repl?
07:48ChouserJoelMcCracken: official (sparse) docs under "Syntax quote" here: http://clojure.org/reader
07:48dnolenhttp://en.wikibooks.org/wiki/Learning_Clojure#Macros
07:49JoelMcCrackenoh, fun
07:49JoelMcCrackenthanks
08:28{newbie}is there away to make a nonpublic def?
08:28{newbie}like the defn- for functions?
08:28kotarak(def #^{:private true} bla 5)
08:28kotarakclojure.contrib.def has defvar and defvar-
08:28{newbie}well
08:29{newbie}it's a mutable collection but it's not a var
08:29{newbie}thanks!
08:29kotarakdef defines a Var...
08:29{newbie}nvm im throwing scala in the mix
08:29{newbie}:\
08:35hiredmanhttp://www.yosefk.com/blog/the-high-level-cpu-challenge.html <-- comments are interesting
08:46Lau_of_DKVery :)
08:53hiredmanclojurebot: ping?
08:53clojurebotPONG!
08:53hiredmanclojurebot: problem?
08:53clojurebotnot a problem, the average bid for it on getacoder is $821.00
08:54cp2lol
08:54cp2i love you clojurebot
08:54hiredmanclojurebot: problem is <reply>"There is no problem in computer programming which cannot be solved by an added level of indirection." -- Dr Maurice Wilkes
08:54clojurebotAck. Ack.
08:55hiredman(except performance)
08:56kotarakclojurebot: problem is also <reply>People have a problem and think "Hey! I'll use a regular expression!". Now they have two problems....
08:56clojurebotYou don't have to tell me twice.
08:58cp2ahh i love a good helping of propoganda: http://itsbetterwithwindows.com/
09:05alinphi
09:05alinpI have the following situation:
09:05alinp(def x (agent nil))
09:05alinp(send x (fn [] nil))
09:06alinpjava.lang.IllegalArgumentException: Wrong number of args passed to: user$eval--502$fn
09:06alinpuser=> (send x (fn [_] nil))
09:06alinpjava.lang.RuntimeException: Agent has errors (NO_SOURCE_FILE:0)
09:06alinpwhat is happening here ?
09:06Chouser,(doc agent)
09:06clojurebot"([state] [state & options]); Creates and returns an agent with an initial value of state and zero or more options (in any order): :meta metadata-map :validator validate-fn If metadata-map is supplied, it will be come the metadata on the agent. validate-fn must be nil or a side-effect-free fn of one argument, which will be passed the intended new state on any state change. If the new state is unacceptable, the validate-fn
09:06Chouserbah
09:06Chouser,(doc send)
09:06clojurebot"([a f & args]); Dispatch an action to an agent. Returns the agent immediately. Subsequently, in a thread from a thread pool, the state of the agent will be set to the value of: (apply action-fn state-of-agent args)"
09:07alinpoh
09:07Chouseryour action-fn needs to take at least one arg, the state-of-agent
09:07alinpyes yes
09:07kotarakalinp: the second time you sent, there is already an error from the first try.
09:07alinpI know that, but if I'm missing it for the first time, my agent is lost ?
09:07Chouseroh, I see. no, the agent is in an error state.
09:07Chouser(count (agent-errors x))
09:08alinpso ... what can I do about it ?
09:08Chouser(.printStackTrace (first (agent-errors x)))
09:08alinpwhat is the usual (elegant) solution for this situation ?
09:08alinpthe only solution is to create other one ?
09:08Chouser,(doc clear-agent-errors)
09:08clojurebot"([a]); Clears any exceptions thrown during asynchronous actions of the agent, allowing subsequent actions to occur."
09:08alinpoh
09:08alinp:)
09:08alinpthis is what I was looking for
09:08alinpthanks
09:08Chousernp
09:09alinpbut, why is this behavior ?
09:09alinpI mean, why it stays in an error state ?
09:09alinpwhy remembers the error state ?
09:09clojurebotwhy not?
09:09Chouserheh
09:09ataggartlol
09:10alinpwhy test ?
09:10Chouserwell, surely you'd want the exception to be available somewhere so you can see what happened... what better place than in the agent itself?
09:10alinpwasn't a bot the clojurebot ?
09:10alinp:)
09:10alinphmmm, Chouser , true
09:10alinpit kind of make it sense, when you put it like this ...
09:11ChouserOther options have been discussed. There'll probably be a way in the future to register a fn that would get called when an exception happens.
09:11alinpyep, like a callback ..
09:11alinpI think it will be useful, for me at least
09:12Chousersure. in that case, perhaps the callback could return a value indicating if the agent's error state should be cleared or not.
09:12alinpyep, nice
09:12Chouseror perhaps that's never necessary and the error state would be cleared automatically and continue, what the callback is handled in another thread
09:12alinpalright then, thanks once again
09:13Chouserdo you have an opinion or use case that would recommend one particular improvement over another?
09:13alinpmaybe a parameter to agent construction
09:13Chousernone of these options would be hard to implement, but rhickey doesn't seem to have a concrete idea of how it should be, and it's not something that would be easy to change once people start using it, so you want to get it right.
09:13alinpthat will indicate if to "forget" the error ... or to handle it in a specific way
09:14Chouserin your use cases is it ever useful for the agent to remain in an error state?
09:14alinpyes, I totally agree, I kind of hate when api is changeing
09:14ataggartin such an exception callback function, one couls just call (clear-agent-errors *agent*) right? So maybe the only thing it should return is a new agent state
09:15alinpwell, I don't think it's usefull at all
09:15alinpI mean, you should check every time if the agent is "dead" or not
09:15alinpright ?
09:15alinpor to call every time the clear function
09:15Chouserataggart: yeah, that's what I was suggesting yesterday, but rhickey seemed to prefer to not rely on the agent-errors/clear-agent-errors api in this new callback mechanism.
09:16Chouserataggart: I'm not sure why.
09:16alinpdefinitely the error state should be loged somehow
09:16ataggartthe main reason I liked it was that it would allow yielding a new agent state
09:16alinpbut, I don't think it should stop the agent working and force me to do extra checking
09:17Chouserit sometimes seems ok (esp. if there's no error callback) to have the agent in an error state so next time you look at it you see the error.
09:17alinpmyes...
09:17alinpyou look at it by sending some function
09:18Chouser,(let [x (agent :ok)] (send-off x #(:oops)) (await x) (println "x is" @x))
09:18clojurebotjava.lang.Exception: Agent has errors
09:18ataggartabsent the callback, erroring out the agent seems like the best alternative. It means you have to babysit the agent, but at least errors are dealt with.
09:18ChouserI mean look at by sending or deref'ing
09:19ataggarthmm... of course wouldn't all this be obviated by simply including try/catch in the action?
09:19alinpof course ...
09:19alinpdamn ... try / catch it takes me back to java ... and I hate it :)
09:19Chouserataggart: almost always, yes. It's often what I do now.
09:20ataggartput that way, your action can "decide" whether or not to error out the agent by propagating the exception, or it could just do what it needs to do to yield the right/new agent state.
09:20ataggartso your "callback" is just built into the action
09:20alinpyep, that's true
09:21Chouserone other case though is if the error comes from outside the action itself. The only time I've seen that is when the agents are being shut down while still trying to send.
09:21ataggartah good point
09:21alinpbtw, how an agent can be shut down ?
09:21alinpis there a special way to do it ?
09:21Chouserall agents and pools can be shut down with 'shutdown-agents'
09:21alinpoh, ok
09:22Chouserthey can't be restarted
09:22alinpbut just one agent can't be closed ?
09:22alinpI know that in fact are java threads
09:22alinpand they can't be closed in a standard way
09:22Chouserno, not really.
09:22cloudheadI'm trying to use the clojure repl, but pressing the arrow keys don't work.. any ideas?
09:22kotarakalinp: no. The run only when sending to it.
09:23kotarakOtherwise they are like an atom or ref.
09:23slashus2cloudhead: rlwrap
09:23kotarakThey just take the storage space
09:23Chousercloudhead: I recommend rlwrap
09:23alinpcloudhead: rlwrapp
09:23alinp:)
09:23cloudheadahah
09:23cloudheadthanks guys
09:24alinpyw
09:40technomancyclojurebot: emacs is best configured for Clojure with instructions at http://technomancy.us/126
09:40clojurebotIn Ordnung
09:43kotaraktechnomancy: did you just overwrite hiredman 's emacs factoids? He'll get grumpy...
09:43cp2technomancy: bla bla bla vim bla bla bla
09:44technomancykotarak: I left "slime is icky" alone; I thought that was the main one he cared about.
09:45technomancyif he cares about his factoids he should add confirmation for overwriting an existing one. =)
09:45kotaraktechnomancy: hehe going for compromise... ;)
09:55hiredman:(
09:56technomancyhiredman: he's your bot; do whatever you will
09:57technomancyhiredman: didn't make it to this week's seafunc. =\ but I did find out Mark Engelberg lives in or around the north seattle area.
09:57hiredmanbeen a busy week
09:58technomancyhiredman: oh I mean _i_ didn't make it
09:58technomancybut yeah
09:58technomancyalso: I can't keep all the clj Marks straight.
09:59hiredmanbeen a busy week means "I thought about it, but before coming to decision I forgot about it"
09:59technomancythat's what happens when meetings are scheduled whenever the organizer feels like it rather than on a regular basis
10:00hiredmanI suppose
10:05cemerickI can't believe how bad the macros that I wrote last summer and fall are. :-(
10:05kotarakcemerick: that means, that you improved your macro-fu! :)
10:06cemerickheh, indeed. It's still sad to know I produced such craziness, though.
10:07cemerickbut yes, it's good to know there's been improvement. I think I've grown more in the last year (!!) of programming in clojure than in the prior 3 programming in Java, python, and scala.
10:09kotarakI have a similar experience. Clojure just makes fun again. :) Its consistency, the use of abstractions, its conciseness, the easy use of maps, sets, vectors.... Awesome, Awesome, Awesome, ... :D
10:10cemerickyeah. I discovered just how fast multimethods were last week. For the longest time, I would set up a cond form or something as long as I had less than a handful of conditions -- then I refactored what was a hotspot from a 4-form cond into a multimethod, and cut runtime of a particular piece down by 80% :-D
10:15kotarakcemerick: :)
10:38ataggartkotarak: yes I find myself giggling aloud a lot lately as I discover new ways of doing things with clj. my co-workers think I've gone batty.
10:39cemerick~max
10:39clojurebotmax people is 164
11:08gnuvinceI'm getting Programming CLojure, SICP and Code Complete 2 this week
11:09gnuvinceComputer Programming Nerd Nirvana :)
11:09kotarakgnuvince: I don't want to be you.... How do you decide where to start? ;)
11:15RaynesI never buy dead tree books.
11:15gnuvincekotarak: Code Complete is probably going to be my first step
11:16gnuvincekotarak: Programming Clojure I mostly read in PDF form and SICP, I want to wait until I get more maths under my belt
11:17kotarakI see... You are prepared. Or how was it? "Luck is where opportunity meets preparation"? Or "Luck favours the prepared"?
11:18gnuvince"Buying book is better when you have a job"
11:18gnuvince:)
11:18gnuvinceIn a few months, I'll be putting my career on hold for at least three years to get a B.Sc. in Computer Science
11:19gnuvinceI figure I might as well buy the books I may want to read right now
11:19rodgertqstill have my original code complete dead tree book
11:19gnuvincebefore I start feeding myself daily with ramen noodles
11:20felzixHow can I turn a string into an integer?
11:20gnuvinceAlso got me a LaTeX reference and a math formulae reference
11:20gnuvince> (Integer/parseInt "3")
11:20gnuvinceclojurebot: oy?
11:20clojurebotIt's greek to me.
11:21gnuvinceuser=> (Integer/parseInt "3")
11:21gnuvince3
11:21gnuvincefelzix: apparently the bot is not very cooperative this afternoon.
11:21gnuvinceheading home
11:21gnuvincelater
11:21hiredman,(Integer/parseInt "3")
11:21clojurebot3
11:21felzixthank you!
11:21hiredman~works on my machine
11:21clojurebothttp://haacked.com/images/haacked_com/WindowsLiveWriter/IConfigMapPathIsInaccessibleDueToItsProt_1446B/works-on-my-machine-starburst.png
11:22gnuvincehiredman: oh duh, > is lambdabot on #haskell :-/
11:22Chouser,(Integer, "3") ; or this
11:22clojurebotjava.lang.Exception: Expecting var, but Integer is mapped to class java.lang.Integer
11:22Chouser,(Integer. "3") ; um, this
11:22clojurebot3
11:23durka42,(Integer/parseInt "3zoo" 36) ; but the constructor only does base 10
11:23clojurebot186216
11:24Chouserah
11:25hiredman,36r3zoor
11:25clojurebot6703803
11:27felzixah, thanks
11:32mebaran151are there any good bindings for a BerkeleyDB like database for clojure
11:32mebaran151something like TokyoCabinet or QDBM would be perfect
11:33Chousermebaran151: rhickey asked that very question just a couple days ago.
11:34hiredmanhttp://justin.harmonize.fm/index.php/2009/03/fifth-static-storage-and-tokyo-cabinet/
11:34hiredmandunno how well that works
11:34cemerickdepending on your worldview, couchdb might fit. We're seeing good results using jcouchdb
11:34mebaran151hmm, maybe that would be a good task for me, porting moneta
11:34dnolenhttp://www.igvita.com/2009/02/13/tokyo-cabinet-beyond-key-value-store/
11:34mebaran151already tried CouchDB for this project: the doc model doesn't fit nearly as well as the BTree model
11:34mebaran151dnolen, yep
11:34dnolentalks about tokyo tyrant, which allows restfull access to tokyo cabinet
11:35cemerickah, cabinet, which is local
11:35mebaran151Cabinet is much faster; seems like memcachedb would be the better hit if I wanted something like Tyrant
11:35dnolentechnomancy is working on clojure httpclient lib. I've used it to interface with couchdb, works well enuf for me.
11:36mebaran151that could be a cool project for me in Clojure though, build a wrapper or at least an interface spec for all these key value stores
11:36mebaran151so you could just plug in Memcache or Tokyo Tyrant or Tokyo Cabinet and things would "just work"
11:37dnolensounds like it, I haven't delved into it myself, but keeping my eye on it.
11:38mebaran151yeah key value stores are much easier to reason about than sql stuff: everything you query will be efficient and the algorithms are obvious
11:38technomancymebaran151: if you don't mind a hosted solution, rhickey has an amazon simpledb lib that works great too.
11:38mebaran151I'm kind of scared of simpledb actually
11:39mebaran151I like to be able to break things on my own box before I start paying in production
11:39hiredmansimpledb is pretty cheap
11:39mebaran151I really wish there were a free version of simpledb, maybe without all the whizbang scaling features, that I could use to test dev against
11:39mebaran151it is, but it's a principle thing...
11:39hiredmanI think rhickey said his last simpledb bill was $0.04
11:40mebaran151everytime I run the test suite, I'd start to cry about the pennies
11:40technomancymebaran151: there's a python simpledb-compatible server you can run locally to test against
11:40technomancyno guarantee of compatibility, but it's worked OK for my initial explorations
11:40technomancyhttp://simpledb-dev.googlecode.com/files/simpledb-dev-0.1.10.zip
11:41dnolenso what do people think about Google Wave? Looks like it'll be easy to code in Clojure.
11:44mebaran151what's it do?
11:44Chouserwell, it's not released yet, so ... everything.
11:44dnolenfairly radical reinvention of distributed communication.
11:45hiredman*snort*
11:46dnolenshort description: email that doesn't suck.
11:46hiredmanuh
11:46technomancyit's more like a framework for building collaborative applications, from what I've seen
11:46hiredmanlooks like a framework for embedding little widgets in webpages
11:46mebaran151it's a bird, it's a plane, it's superapp!
11:46dnolenwell not really
11:46hiredmanhardly revolutionary
11:47technomancymebaran151: don't forget a dessert topping and floor wax.
11:47dnolenit's protocol, and their opening the client and the server components.
11:47mebaran151it sounds like basecamp a little bit
11:47hiredmanhttp://googlewavedev.blogspot.com/2009/05/introducing-google-wave-apis-what-can.html
11:47dnolenhiredman: you definitely missed the point, it's not about embedding widgets.
11:47mebaran151which was limitedly useful, but nothing beats scripting the hell out of .procmail
11:47hiredmanit definitely is
11:48durka42but what's built in seems to be about combining email, instant messaging and twitter
11:48dnolendurka42: that's not what it is either.
11:48mebaran151didn't gmail mostly do that...
11:48hiredmanI think you are confusing apps built with wave with wave
11:48dnolenon the web feeds are becoming popular: delicious, flickr, twitter, facebook.
11:48clojurebotdelicious is http://delicious.com/clojurebot
11:48dnolenthey're all reinventions of the same damn thing.
11:48dnolenmy email is a feed.
11:49drewrdnolen++
11:49dnolena wave a generic feed.
11:49dnolenis a generic.
11:49hiredmanuntil they release something...
11:51mebaran151just another quick question: in a functional language like clojure, what's the best way of maintaining something super stateful like a database connection or io descriptor? In OO I would just pass around an object wrapping the database api, but in clojure, should I cleverly use a closure?
11:51Chousermebaran151: I've been using maps for such things.
11:51hiredmanmebaran151: take a look at clojure.contrib.sql
11:51drewrmebaran151: You still pass around an object.
11:52mebaran151but where do I keep the descriptor? (I haz no instance vars...)
11:53drewrI pass it as an argument to each function.
11:53drewrBut, like Chouser said, I decorate it with a map so I can add metadata, etc.
11:53ChouserI've been using maps with keys like :socket, :stream, :handlers, etc.
11:54ChouserI'm not yet sure if that's the best way, but it certainly works.
11:54cp2i was going to say something witty but i forgot what it was
11:54drewrThen I create macros around those functions that make working with the whole mess a lot simpler.
11:54Chouserthe objects that are inherently mutable (like streams) are fine as values in the map
11:55Chouserthe values that are inherently immutable (like port/address of the socket) are fine as values as well
11:55Chouseranything than needs to change (number of messages sent, or whatever), I use some kind of mutable reference for the value. Most often an atom, but refs make sense sometimes too, as do agents.
11:56mebaran151but couldn't I instantiate my get and set functions as a closure, that sort of absorbs this map, which itself would include the io descriptor?
11:56mebaran151so I could just say something like (get "key123")
11:56hiredmanmebaran151: look at clojure.contrib.sql
11:57mebaran151or should I be using a macro for this sort of thing (i'm pretty new to LISP macros so I don't know where to use them yet)
11:57mebaran151hiredman, will do
11:57Chousermebaran151: I haven't needed macros for such things yet
11:57technomancymebaran151: rule 1 of macros: don't write macros
11:58Chousermebaran151: but yes, a set of closures that close over your state are an option.
11:58technomancyrule 2 (for advanced usage): don't write macros _yet_
11:58Chouserrule 3: most of that macro you wrote belongs in a function
11:58mebaran151makes sense (I have enough trouble fighting emacs)
11:58hiredmanmebaran151: the short answer is clojure has mechanisms for lexical and dynamic binding
11:59hiredmanlexical binding is at function creation time, and dynamic is at function call time
11:59wwmorgan#=(foo java.lang.String) : In the evaluation of this form, foo is passed a Symbol. Is there a way to make it so that foo is passed a Class instead?
11:59hiredmanwwmorgan: use (Class/forName "String")
12:00hiredmanor whatever
12:00wwmorganhiredman: hm. I think foo would be passed a list object in that case?
12:00hiredmanmebaran151: having get close over the db connection is annoying because then you have to pass around the closure
12:01hiredmanand you have seperate sets of closures for each connection
12:01Chouserwwmorgan: you're playing with deep magic there, using #=(). Are you sure you want/need to?
12:01hiredmanwwmorgan: inside foo, use Class/forName
12:02mebaran151hiredman, usually there should be only a finite number of connections, so that seems fine
12:02technomancyChouser: I thought that was a typo; what _is_ it?
12:02hiredmanmebaran151: did you look at that link I pasted about tokyo and clojure?
12:02wwmorganChouser: not at all :-). I'm looking at print-dup for serialization.
12:02mebaran151yep, but they used a nasty macro to preset the database
12:02hiredmanuh
12:03hiredmanmebaran151: you misunderstood
12:03hiredmana macro cannot represent a database
12:03hiredmanthe macro is merely sugar over a binding form
12:03Chousertechnomancy: #=() allows for evaluation at read-time (so before even macros kick in), but with odd rules.
12:04technomancyiiiinteresting
12:04Chouser...like class names are not yet resolved.
12:04Chouserwwmorgan: well, that's the one context where you may be justified in playing with #=(). :-)
12:05hiredmanmebaran151: so the get function closes over *db* which is nil, but then you use binding to bind *db* to the database connection dynamically
12:05Chouserwwmorgan: in which case hiredman is right -- if you know that arg is a class name, and you need it to be a class, then something like (Class/forName arg) or (resolve arg) may be what you want.
12:06mebaran151I see
12:06hiredmanmebaran151: which is not to say the code he ended up posting is all good
12:06mebaran151so essentially it's dynamic scope?
12:06hiredman$%@#
12:07hiredman...yes
12:07Chouserhiredman: deep breaths.
12:07mebaran151sorry!
12:07hiredman,(doc binding)
12:07clojurebot"([bindings & body]); binding => var-symbol init-expr Creates new bindings for the (already-existing) vars, with the supplied initial values, executes the exprs in an implicit do, then re-establishes the bindings that existed before."
12:10wwmorganChouser: actually my use case requires calling into java library functions whose implementation I can't change. However, I can change the print-dup methods for our objects to not use #=. That's what I'll try next.
12:13Chouserwwmorgan: or have the contents of the #=() be different -- that can be adjusted with a defmethod I believe.
12:59mrsoloprogramming clojure shipped! woot
16:25lgasare there any good resources for best practices when designing programs/solution in clojure? e.g. I am trying to write a program to do automatic thesaurus generation based on frequency of words occuring together and one obvious approach would be to have a map with the key being word pairs and the value being an agent that gets incremented every time that pair is encountered but this is my first attempt to solve a real world concurr
16:25lgasproblem in clojure so I have no basis for knowing if this is a good approach or not....
16:29cmvkkwriting good concurrent programs is a pretty difficult problem
16:31lgasindeed
16:31lgasI can see how a lot of the concepts in clojure help make it more managable at a conceptual level, but putting the pieces together in practice is not as easy. For now I suppose I'll just try the approach that occured to me and see if it turns out to be good or not.
16:31cmvkkin that particular case, if all you're doing is gathering data about frequency of word pairs you'd probably be better off generating individual maps for sections of the input text concurrently, then merging them
16:32cmvkkbut i'm not too sure either way
16:33lgasThat makes sense. I'll try generating individual maps for each chunk of words I'm dealing with and then maybe send those to an agent to be merged into the master map...
16:52slashus2,(time (+ (int 1) (int 1)))
16:52clojurebot2
16:52clojurebot"Elapsed time: 0.147 msecs"
16:52slashus2,(time (+ 1 (int 1)))
16:52clojurebot2
16:52clojurebot"Elapsed time: 0.161 msecs"
16:53slashus2Must not be the latest revision. It seems to reflect when I did the first one on build 1381.
16:55slashus2Wait this seems to be only with /
16:55slashus2,(time (/ (int 1) (int 1)))
16:55clojurebot1
16:55clojurebot"Elapsed time: 0.556 msecs"
16:55slashus2,(time (/ 1 (int 1)))
16:55clojurebot1
16:55clojurebot"Elapsed time: 0.119 msecs"
16:56cadshey, do you guys think currying would be useful in clj, or would the strong presence of variadic functions just make it ackward to have to think about?
17:04cadswith fixed arity functions we can write (def add-five-things (curry (fn [x1 x2 x3 x4 x5] (+ x1 x2 x3 x4 x5))), then we can say (def add-three-things-to-ten (add-five-things 0 10)), and then (def add-one-thing-to-twelve (add-three-things-to-ten 1 1)), and so on, where the function yielded by a curry knows how to curry itself further until it's built up enough arguments to evaluate the whole function
17:05cadsI think those examples don't do much to motivate actually using curried fns though :)
17:06hiredman,(doc partial)
17:06clojurebot"([f arg1] [f arg1 arg2] [f arg1 arg2 arg3] [f arg1 arg2 arg3 & more]); Takes a function f and fewer than the normal arguments to f, and returns a fn that takes a variable number of additional args. When called, the returned function calls f with args + additional args."
17:06hiredmanI use it all the time
17:07cadsthere's a difference between currying and partial application: a partial application is a function that will finish a computation and yield a value in one shot of additional parameters.
17:07cadsWhile curry will yield a function when not given enough parameters to complete the original function, which will in turn take more params
17:08cmvkki don't see the difference, other than that one is automatic I guess
17:08cadsthe problem with variadic functions and currying is that we don't know when we build a curry how many arguments the user will want to pass
17:08hiredman,((uncurry + 1) 2)
17:08clojurebotjava.lang.IllegalArgumentException: Wrong number of args passed to: sandbox$uncurry
17:09hiredman,(((uncurry +) 1) 2)
17:09clojurebot#<sandbox$uncurry__2158$uc__2160 sandbox$uncurry__2158$uc__2160@163542c>
17:09hiredman,((((uncurry +) 1) 2))
17:09clojurebot3
17:09cads,(doc uncurry)
17:09clojurebot"([x]); applied to a function it returns a function that will continue partially applying until it is called with no arguments"
17:09cadsthat's curry!
17:09hiredman~transform
17:09clojurebottransform is http://github.com/hiredman/odds-and-ends/blob/8a84e6ddbad9d71f714ba16c3e1239633228a7eb/functional.clj
17:09hiredmancads: yeah well, I wasn't paying too close attention
17:09cadswait, no it's not, it's a kind of curry
17:10cmvkkin any case, having automatic currying doesn't work with multiple-arity functions very well
17:10cadsyeah, in the above case we must wrap our result in an extra set of parens
17:10hiredman,(pl ?+ $ 1 $ 2 $ 3 $ nil)
17:10clojurebotjava.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn
17:11hiredmanbah
17:11chessguyand it tends to make for messy error messages with known-arity functions too, cmvkk
17:11chessguy(a la haskell)
17:11slashus2hiredman: I thought at first that the reflection was because the new reduce function wasn't overloaded to include Integer, but that doesn't seem to be the case.
17:11hiredmanslashus2: huh?
17:12cadsin my implementation thing, for variadics we have to say something like ((((curry * 3) 2) 4) 2 1 :end) => 48
17:12slashus2hiredman: In revision 1381, it seems that something like (/ (int 1) (int 2)) will reflect when you activate *warn-on-reflection*
17:12cadsand I am hard pressed to think of fixed arity functions with more than 2 parameters in clojure, everything variadic :)
17:12slashus2Where that wouldn't occur before.
17:13slashus2,(time (/ (int 1) (int 2)))
17:13clojurebot1/2
17:13clojurebot"Elapsed time: 0.458 msecs"
17:13hiredman~latest
17:13clojurebotlatest is 1381
17:13hiredmanr1381
17:13hiredmanr1380
17:13cadshey chessguy
17:14chessguyhi
17:14hiredman,(macroexpand '(pl ?+ $ 1 $ 2 $ 3 $ nil))
17:14clojurebot(do ((uncurry +) (1 (2 (3 nil)))))
17:14hiredmanhmmm
17:15hiredman,(pl (reduce ?+ '(1 2 3)))
17:15clojurebot#<sandbox$uncurry__2158$uc__2160 sandbox$uncurry__2158$uc__2160@3fa50b>
17:15hiredman,(pl ((reduce ?+ '(1 2 3))))
17:15clojurebotjava.lang.ClassCastException: sandbox$uncurry__2158$uc__2160 cannot be cast to java.lang.Number
17:16hiredmanslashus2: sorry I dunno
17:17slashus2I am trying to figure it out, but my limited understanding of when clojure decides to reflect makes it difficult.
17:27slashus2hiredman: It seems to only do it when you use (int 5) replace 5 with any number.
17:27slashus2,(class (int 5))
17:27clojurebotjava.lang.Integer
17:28chessguy,(doc int)
17:28clojurebot"([x]); Coerce to int"
17:36slashus2Doesn't seem to do it with (/ (Integer. 5) (Integer. 5))
17:42Chouserslashus2: are you sure the reflection behavior of (/ (int 5) (int 5)) has changed?
17:43Chouserseems to warn in 1.0.0 as well
17:43slashus2You are correct.
17:43ChouserI think the issue is that there's no divide method for int,int
17:43slashus2I was getting ready to check back to 1376
17:43ChouserI guess if you want integer division you can use 'quot'
17:44slashus2:-/
17:44Chouser(show clojure.lang.Numbers "divide")
17:44slashus2It seems that (/ (int 1) (int 2)) would be faster than (/ 1 (int 2))
17:44slashus2Misconception I guess.
17:45Chouserthere is also unchecked-dividie
17:45Chouserunchecked-divide
17:46hiredmanChouser: rhickey seems to think going to unchecked-whatever is a bad idea unless you specificly what it's behaviour (truncating, etc)
17:46Chouseryeah
17:47Chouserquot doesn't use primitives -- it boxes, so that's slow
17:47slashus2Same thing exists with 1376 as well. I guess I was mistaken.
17:48Chouser(unchecked-divide (int 5) (int 5)) is not quite twice the speed of (/ (int 5) (float 5))
17:48slashus2Are we going to create a divide method with int int
17:49Chouserwe?
17:49slashus2The community?
17:49Chouseror a quot that takes primitives?
17:50hiredmanor build a clojure machine out of a fpga
17:51slashus2It is strange that (/ 1 2) is about 5 times slower than (/ (int 1) (int 2))
17:52Chousernot that strange. boxing is slow.
17:52Chouseroh
17:52slashus2Chouser I meant it the other way around.
17:52slashus2sorry
17:52Chouseryeah, I was about to correct myself
17:53Chouserboxing is quite a bit slower than primitive math, but reflection is *really* slow.
17:53Chousercompared to compiled direct calls.
17:55slashus2I guess this is expected behavior? So make sure that both of the arguments are not coerced?
17:55Chouserso, for now your best route (if you're dealing with primitives already, anyway) is probably to coerce one of your ints to a float or something so that you can get a primitive call
17:56slashus2Not something to be fixed?
17:56Chousernext best would be to use quot -- that gives clearly defined behavior and avoids reflection, so only costs you the boxing.
17:57Chouseroh, you could certainly raise the issue. I don't do enough math stuff to know what's best, but rhickey certainly cares about numeric performance.
17:57slashus2Someone raised it in the group, but it has no attention yet.
17:57slashus2Their observation that it was different in 1376 was incorrect.. I think.
17:58Chouserthe two solutions that seem most likely would be either int,int and long,long etc. divide methods, or primitive quot methods.
17:58slashus2Chouser: Yes, I just added an int int method and it now works with the same performance.
17:58arohneris there a function that works like str-join, but for collections?
17:58Chousernice
17:59slashus2I wish I had a CA turned in.
17:59arohneri.e. (join [1 3 5] :a) => (1 :a 3 :a 5) ?
17:59Chouser,(interpose 'x (range 5))
17:59clojurebot(0 x 1 x 2 x 3 x 4)
17:59hiredmanclojurebot: do you have any life lesson advice?
17:59clojurebotlive every week, like it is shark week!
17:59arohnerChouser: thanks!
18:00Chouserarohner: do you use repl-utils? (source str-join)
18:00arohnerah, that's a good idea
18:00arohnerI did find-doc before asking the channel :-)
18:01ChouserI mean, feel free to ask anytime, but I thought I'd mention it.
18:01arohnerit's good advice, thanks
18:06slashus2Chouser: http://groups.google.com/group/clojure/browse_thread/thread/a767baaa0b3b17eb is where the issue was brought up. I replied with as clear of explanation as possible.
18:07slashus2I think that is the problem he was having here, but I could be mistaken.
18:08Chouserhm, I didn't realize 'count' had an inline definition, so it can "return" a primitive.
18:09slashus2I guess that is what happened.. It returned an int primitive.
18:10slashus2This problem could be causing quite a bit of performance loss in people's code who don't expect this behavior.
18:10Chouseranyway, in that case where he's dealing largely with boxed things and integers anyway, he should probably use quot
18:12slashus2,(time (/ 5 5))
18:12clojurebot1
18:12clojurebot"Elapsed time: 0.114 msecs"
18:12slashus2,(time (quot 5 5))
18:12clojurebot1
18:12Chouserbut you're right, what changed was 'count' got an inline definition
18:12clojurebot"Elapsed time: 0.149 msecs"
18:12slashus2Ahh, that was the change that I was looking for.
18:12slashus2Makes sense now.
18:22Chouserthe most fun thing about jna is errors don't result in wimpy little stack traces and a new repl prompt. Instead you get full-on segfaults.
19:34lgasI'm trying to get used to working with clojure in emacs with slime... is there a way to define namespaces/uses/imports/refers/etc such that you can just slime-eval-buffer (or do it an expression at a time or whatever) to get everything in your source file evaluated into the repl? Right now I have problems where I have (ns .. (:use .. (..))) declarations that I have to repeat manually with just (use '..) to get them in scope in the
19:34lgasrepl...?
19:43durka42i'm confused
19:43durka42when you eval a buffer with (ns ...) in it, it doesn't work?
19:45lgasyes, it gives me a "Unable to resolve symbol: re-split" (for example) even though in my (ns ..) I am :use'ing clojure.contrib.str-utils.
19:47durka42for re-split that's used in the buffer?
19:47arohnerlgas: how are you loading the buffer in slime?
19:47durka42or that's used in the REPL after eval-buffer'ing?
19:47durka42if the latter, you need to in-ns in the REPL
19:47arohnerI use C-c C-l <enter>
19:48arohneri.e slime load file rather than slime eval buffer
19:50lgasYeah, C-c C-l <enter> on this file: http://pastie.org/493608 gives me the "Unable to resolve symbol: re-split" error.
19:51lgasbut if I manually (in-ns 'wordformgen) and then (use 'clojure.contrib.str-utils) it's fine
19:51arohnerhmm...
19:51arohnersee if
19:52arohner(ns wordformgen (;use clojure.contrib.str-utils) (:use clojure.contrib.combinatorics)) works
19:53lgasI assume that ; should be a : ?
19:54arohneryes, sorry
19:54lgasI think that worked... though I have another error now, so let me see
19:55lgasok yeah that got it
19:56lgasthanks a bunch
19:57arohnernp
20:37cadshey hiredman, I like your functional.clj
20:38cadsI think it's time I actually played around with a zip structure, because those methods look neat
20:47chewyin swank-clojure what's the difference between doing a load (c-c c-l) and a compile (c-c c-k)?
20:51vychewy: I'm not sure but there shouldn't be a difference, since Clojure is directly compiling the snippets to byte code, no difference between interpretation and compilation, AFAIK.
20:53lgaswhy would (count (line-seq rdr)) work but (map println (line-seq rdr)) throw a "Stream closed" IOException (and yes, I'm using new readers for both tests)
20:54durka42~map
20:54clojurebotmap is *LAZY*
20:55lgasok... why would map being lazy cause the IOException? I would expect the laziness to just cause nothing to happen until it was forced...
20:55durka42exactly. and the stream is gone by then
20:55lgasah ok I get it
20:55lgasthanks
20:56durka42you can wrap a doall, or use doseq instead of map
20:56durka42~def line-seq
20:58durka42hm, line-seq is also lazy
21:02lgaswell, in my case, I was calling a function that had the (with-open ... (map (lazy-seq ..))) from the repl, so I guess that was forcing the map which was forcing the lazy seq, but it was forcing it after the stream was already gone
22:40jdzgz on the book, Stuart
22:40jdz!
23:25djpowellIs there any way to get the class name of the implementation of a function from inside that function?
23:29djpowellI guess I can do it by using (def (fn thisfn [ ...
23:36hoeckdjpowell: or just (defn me [] (type me))