#clojure log - Mar 07 2009

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

0:36 * abrooks_ thinks Clojure stream notation should be harder for the querty/English crowd for once: �map / �filter

0:37 cmvkk: well if we're going to use weird characters, I think we should use the snowman.

0:37 abrooks: I say that as a member of the querty/English crowd...

0:37 cmvkk: Oh, of course.. how could I have overlooked that. http://onclojure.com/2009/03/05/a-monad-tutorial-for-clojure-programmers-part-1/;-)

0:38 Ooops...

0:38 cmvkk: Oh, of course.. how could I have overlooked that. /;-)

0:38 cmvkk: heh, i was hoping there was somehow a snowman i missed in that monad tutorial.

0:38 abrooks: I just need to figure out the compose key for "snowman"

0:39 The X11 compose/multi-key is a great mechanism for accessing non-primary symbols.

0:40 (...map... foo bar)

0:40 Actually, I liked the =map= and =filter= myself.

0:41 * abrooks catches up with the part of the IRC log where rhickey says "nothings off the table at this point except non-ascii"

0:42 abrooks: Look, if non-ascii was good enough for APL it's good enough for Clojure. ;-D

0:43 cmvkk: i think we should utilize the wide range of unicode available, and make it so that every core function is only one character long.

0:44 you could accomplish that with chinese characters alone!

0:52 abrooks: cmvkk: In my own code I've found it nice to use unicode symbols in Clojure (mostly Project Euler) but I think it's the right decision to keep the core language free of unicode.

0:53 cmvkk: I know you were having fun. :)

0:54 cmvkk: of course...but i do welcome a day when unicode input is so easy that keeping non-ascii characters out of a language isn't necessary anymore

0:57 durka42: is c.c.monads broken?

1:02 m-lift doesn't seem to work because m-bind is nowhere to be found

1:02 ,(use 'clojure.contrib.monads)

1:02 clojurebot: java.io.FileNotFoundException: Could not locate clojure/contrib/monads__init.class or clojure/contrib/monads.clj on classpath:

1:12 durka42: never mind

1:35 Raynes-: durka42: You are broken :>

1:45 replaca: Q: so, I'm updated to the lazy stuff and lazy-cons seems to be gone, but cons isn't really lazy

1:45 what's the right stategy?

1:46 *strategy

1:49 cmvkk: lazy-seq?

1:49 replaca: ahh, ok.

1:50 is there a doc that outlines the effect of the changes (or a google message)?

1:50 I wasn't paying very close attention when all that happened

1:50 cmvkk: http://clojure.org/lazy is i think the correct one

1:51 replaca: RTFM, Tom :-)

1:51 thanks, cmvkk!

1:51 cmvkk: actually, i'm not sure how you even access that page from anywhere.

1:52 brennanc: http://paste.lisp.org/display/76606

1:52 replaca: yoou mean, besides getting someone to post a link in IRC? :-)

1:52 cmvkk: that's where I got it from...

1:53 brennanc: can someone explain this? It's from the Programming Clojure book. I don't understand what is getting passed to map and how it is even valid.

1:53 pt is something like [5 10]

1:53 replaca: we're all part of a secret society!

1:53 cmvkk: the list being passed in is [(pt 0) (pt 1) 1 1] it seems

1:53 brennanc: ([5 10] 0) is not a valid expression though

1:53 cmvkk: and the fn is #(* point-size %) which is just (fn [x] (* point-size x))

1:53 hmm

1:54 brennanc: (* point-size [5 10] 0) makes no sense to me

1:54 cmvkk: wait, what does (pt 0) return?

1:54 brennanc: pt is not a function operand so I don't get how it is even valid

1:55 pt is passed as [5 10] in the example

1:55 cmvkk: ohhh!

1:55 replaca: brennanc: ,([5 10] 0)

1:55 ,([5 10] 0)

1:55 clojurebot: 5

1:55 cmvkk: yeah, vectors are functions of their indexes.

1:56 replaca: I didn't know that, but guessed from context

1:56 brennanc: ahhh

1:56 replaca: pretty cool

1:56 brennanc: I never would have guessed that one, but it makes perfect sense now

1:56 replaca: brennanc: this is where the REPL helps: if it doesn't seem right just type it in and see what happens :-)

2:11 Raynes-: When a function is screwing up, I always break it down and evaluate every piece in the REPL. <3 REPLs.

2:12 brennanc: yeah, I got the result and knew it worked, just didn't understand how it was valid :)

2:13 or what the logic was behind it

2:13 cmvkk's explanation cleared it up instantly

2:16 Raynes: brennanc: In case you didn't know it, maps are the same way.

2:17 brennanc: yup, thanks

2:17 Raynes: ,({:akey "This is a value." :anotherkey "This is another value."} :akey)

2:17 clojurebot: "This is a value."

2:17 Raynes: That's always fun.

2:17 brennanc: anything else it works with?

2:18 Raynes: I don't think so.

2:18 brennanc: k

2:20 hiredman: ,(:key {:key 1 :a 2})

2:20 clojurebot: 1

2:20 brennanc: ok, got a bunch of questions about this one

2:20 (defn move [{:keys [body dir] :as snake} & grow]

2:20 hiredman: ,('a {'a 1 'b 2})

2:20 clojurebot: 1

2:20 hiredman: that is hash destructuring

2:21 which you kind find out about on the special forms page on the website under let

2:21 brennanc: where would I find docs for that?

2:21 hiredman: clojurebot: destructuring?

2:21 clojurebot: destructuring is http://clojure.org/special_forms#let

2:21 brennanc: thanks, will read

2:22 hiredman: that fuction takes a hash {:body _ :dir _}

2:23 body is bound to (:body hash) and dir likewise, those whole hash is bound to snake

2:23 then it takes a variable number of other arguments that are availble in a sequence bound to grow

2:25 brennanc: the & var-name is another way of saying it is optional, right?

2:27 hiredman: that and it binds to a sequence

2:28 ,((fn [ & x ] x) 1 2 3 4)

2:28 clojurebot: (1 2 3 4)

2:28 brennanc: ,((fn [& x] x) )

2:28 clojurebot: nil

2:29 brennanc: ,((fn [& x] x) (list))

2:29 clojurebot: (())

2:33 replaca: I was using nil? alot in loops to check for the empty list! :-(

2:34 brennanc: ,(identical nil ())

2:34 clojurebot: java.lang.Exception: Unable to resolve symbol: identical in this context

2:34 brennanc: ,(identical? nil ())

2:34 clojurebot: false

2:35 replaca: yeah, nil? foo used to work when you ran off the end of a list, but not anymore!

2:35 and the result tends to be an infinite loop/recur

2:35 hiredman: well, it still does if you (seq ...) the list

2:35 ,(doc next)

2:36 clojurebot: "([coll]); Returns a seq of the items after the first. Calls seq on its argument. If there are no more items, returns nil."

2:36 replaca: or you can just use empty?

2:36 hiredman: :(

2:36 replaca: not good?

2:37 hiredman: asthetically unpleasing

2:38 replaca: hmm, to check the end of the list? I don't get it

2:38 brennanc: the sequence video talks about it towards the end

2:38 ISeq interfaces will return nil if you try to get another element an there is nothing there

2:39 hiredman: erm

2:39 brennanc: ...hopefully I remembered that correctly or am saying it right

2:39 hiredman: things have changed

2:39 brennanc: lol

2:39 replaca: that went out with laziness

2:39 brennanc: yet another inconsistency

2:39 replaca: that's what was breaking in my code

2:39 hiredman: it used to be impossible to have empty sequences, if you tried you just got nil

2:40 now it is possible

2:40 brennanc: ,(rest [])

2:40 clojurebot: ()

2:40 brennanc: it used to return nil

2:40 cmvkk: ergh.

2:41 replaca: hiredman: are you suggesting that I should use next instead of rest?

2:41 cmvkk: so i have these two functions i have to call hundreds of thousands of times in a row, and they both are exactly the same but for a caching system.

2:41 hiredman: that is one way t ogo

2:41 if you don't need full laziness

2:41 cmvkk: one uses a ref with a vector and assoc to create a ring buffer. the other stores only the immediately previous value and its number as an atom, in a vector of size 2.

2:42 replaca: hiredman: but empty? is bad? that still confuses me

2:42 hiredman: not bad

2:42 cmvkk: so the first one updates two refs and uses assoc, and the second one updates one atom and replaces the vector inside entirely.

2:42 but the ref one is FIVE TIMES FASTER than the atom one.

2:42 atoms are supposed to have less overhead than refs!

2:42 hiredman: for low contention

2:42 (I believe)

2:43 if you program does nothing but hit the atom a ref will perform better

2:44 cmvkk: well it grabs the previous value, does some unchecked math against it and different value, then stores the resultant value where the previous value used to be.

2:44 hiredman: actually, I should say, I don't know that for a fact

2:44 brennanc: what's the point of atoms? why can't you just call def again if you want to set it to something else?

2:44 hiredman: ick

2:44 brennanc: def once

2:44 and never again

2:44 cmvkk: because it might be concurrent later.

2:45 brennanc: cmvkk: what do you mean by that?

2:45 hiredman: you should only ever re-def stuff in the repl

2:45 cmvkk: re-deffing is not thread safe....is it? i don't think it is?

2:45 hiredman: and def only operates in the global space

2:45 Chouser: atoms make sure you're transitioning in a consistent way

2:46 no read-calc-write race condition errors with atom and 'swap!'

2:46 cmvkk: in any case, i tried making a version that used two refs and did the same things as the atoms, and it was slower than the atom version.

2:46 so i have no idea what it is about the ring buffer version that's so much faster.

2:46 hiredman: ,(let [a (atom 0)] (swap! a inc) @a)

2:46 clojurebot: 1

2:47 cmvkk: it's actually only a small part of the program, but it slows the thing down from 22 seconds to 97 seconds.

2:48 Chouser: re-deffing is atomic -- you're not going to end up in some broken state. but (def foo (inc foo)) has a race

2:50 brennanc: so an atom will wait until other transactions are done before it will set its value?

2:51 hiredman: functional programming is a thing of elegence and beauty, re-defing is like using a non-synthetic motor oil

2:51 atoms set their value atomically

2:51 compare and swap

2:53 Chouser: atoms don't cooperate with transactions. 'swap!' has a side-effect.

2:54 cmvkk: it would be nice if atoms could synchronize somehow

2:54 Chouser: then they'd be a ref. :-)

2:54 hiredman: word

2:55 cmvkk: well i'm changing the value of two different numbers, and i want to do it atomically. Should I just use two refs instead of an atom with a size-2 vector?

2:55 which would be faster?

2:55 hiredman: sounds like time for a profiler

2:56 cmvkk: well i'm using a 'time' thing. but like i said: refs with a ring buffer = 22 seconds, one atom with a size-2 vector = 97 seconds.

2:56 something seems awfully off about that.

2:56 Chouser: you've got *warn-on-reflection* on?

2:57 cmvkk: nope, let's try that.

2:58 haha, thanks Chouser.

2:59 Chouser: reflection hurts, eh?

2:59 cmvkk: the difference between the two fns: on the atom one, i wasn't wrapping the result of the atom deref in (int ...)

2:59 so unchecked-add and unchecked-divide couldn't resolve.

3:01 this renderer is still quite a bit slower than real time, which is disappointing, but at least it's getting there...

3:01 I can do 8 seconds of music in 20 seconds now.

3:03 Chouser: reflection is most punishing, but boxing and unboxing are a next.

3:03 You're sure you're not doing either more than necessary?

3:03 that's a somewhat tougher question to answer in my experience.

3:03 cmvkk: I have no idea. well reflection is okay. the only things left that warn about that are the parts that actually write data out to file.

3:03 and i know that's not the bottleneck.

3:04 Chouser: ok, that's good.

3:04 cmvkk: the way the system is designed makes it hard, i think, to make sure things are going through correctly.

3:04 it uses lots of functions that take closure arguments and return new closures that call the argument closures, etc

3:05 ints are 'supposed' to be returned a lot, but who knows.

3:05 Chouser: every clojure functions takes and returns only boxed numbers, never primitives.

3:05 cmvkk: fns never return primitives?

3:05 Chouser: right

3:05 always Objects

3:06 cmvkk: so what DOES return primitives? just (int ...) and all those unchecked-math functions?

3:06 Chouser: in a few limited circumstances you can use a macro or better definline to factor out common code without losing primites.

3:07 only locals and java interop can use primitives.

3:07 cmvkk: :( do you think this has a chance of changing ever?

3:07 Chouser: as soon as the JVM gets tagged numbers, which apparently won't be very soon at all.

3:08 brennanc: how popular is clojure? any companies using it yet?

3:08 cmvkk: if you call (int ...) on something that's already an int, that's not a performance hit is it?

3:09 hiredman: rich has mentioned a special function interface for return various primitives numbers

3:09 Chouser: brennanc: some companies are using it, yes.

3:09 I was asked about it in job interview the other day.

3:10 brennanc: that's cool. my boss is a developer and thinks PHP is the best language ever. lol

3:10 Chouser: I really shouldn't be up. good night, all.

3:11 albino: heh, go php

3:11 brennanc: I'm getting sick of writing (for $i=0; $i<$something; $++)

3:11 hiredman: :(

3:12 I started looking at some kind of "write something like clojure, compile to php" scheme

3:12 brennanc: or having to store expressions into temp variables that only get used once because it won't let put an expression in certain forms

3:13 hiredman: so it takes a list and outputs php code?

3:14 hiredman: more or less

3:14 Chouser: brennanc: http://groups.google.com/group/clojure/msg/1d215a79a697a68a

3:14 hiredman: I have been ignoring php for a while, but when I have to deal with it again, I may start it again

3:15 my current idea is clojure->json->interpreter written in php that "executes" json

3:16 that way I would not have to write a parser

3:16 brennanc: I wrote some small code that is a forth like interpreter and ported it to PHP, javascript, and actionscript

3:16 not a whole lot of api in it but got the parsing done and everything

3:17 hiredman: then you should write the clojure->php bridge

3:17 :)

3:17 brennanc: I'd be tempted with what I have to deal with at work. :)

3:18 only been learning clojure for about a week now. have to give it at least another week. ;)

3:19 hiredman: but it would help you learn, ask Chouser.

3:21 replaca: goodnight all! Happy late-night clojuring

5:57 Lau_of_DK: Hey guys

5:58 hoeck: hey lau

5:58 kotarak: Ol�, Se�or Lau.

5:59 Lau_of_DK: Assume I have a datastructure like ({:alpha 1 :beta 2 :gamma 3} {:alpha 4 :beta 5 :gamma 6}) and I want to export that to CSV: 1,2,3,4,5,6 in that order - is there an elegant way to accomplish that?

5:59 Ola mon Kota

5:59 Und mein The Hoeck :)

6:00 hiredman: mapcat vals

6:00 kotarak: ,(apply str (interpose "," (map val (concat {:alpha 1 :beta 2 :gamma 3} {:alpha 4 :beta 5 :gamma 6}))))

6:00 clojurebot: "1,2,3,4,5,6"

6:02 Lau_of_DK: ,(apply str (interpose "," (map val (concat {:zeta 1 :beta 2 :gamma

6:02 3} {:zeta 4 :beta 5 :gamma 6}))))

6:02 clojurebot: EOF while reading

6:02 Lau_of_DK: ,(apply str (interpose "," (map val (concat {:zeta 1 :beta 2 :gamma

6:02 3} {:zeta 4 :beta 5 :gamma 6}))))

6:02 clojurebot: EOF while reading

6:02 Lau_of_DK: Hmm, why the bork ?

6:03 What Im trying to say is, that it works by the assumption that your keys are alphabetically stored, mine aren't

6:03 hiredman: (comp sort mapcat)

6:03 kotarak: ,(apply str (interpose "," (mapcat vals (list {:alpha 1 :beta 2 :gamma 3} {:alpha 4 :beta 5 :gamma 6}))))

6:03 clojurebot: "1,2,3,4,5,6"

6:04 kotarak: sorted-map?

6:04 Lau_of_DK: Funny, on my rev it gives "3,1,2,6,4,5"

6:05 kotarak: There was a change in size when array-map is used by {}, I think.

6:05 Lau_of_DK: that might be it - anyway, Im inspired, thanks

6:36 cgrand: ,(apply str (interpose "," (mapcat #(map % [:alpha :beta :gamma]) (list {:alpha 1 :beta 2 :gamma 3} {:alpha 4 :beta 5 :gamma 6}))))

6:36 clojurebot: "1,2,3,4,5,6"

7:57 Lau_of_DK: Thanks alot cgrand

10:21 RadioApeShot: Is there a predicate which returns true for anything which produces a seq when passed to the seq function?

10:21 kotarak: coll? might be a first guess.

10:22 RadioApeShot: Ah

10:22 I was using col?

10:22 That is just what I want

10:22 Thanks

10:22 kotarak: #(or (coll? %) (seq? %))

12:46 blbrown: anybody there

12:47 kotarak: yup

12:47 durka42: indeed

12:47 nifty bus wi-fi

12:48 hipertracker: Do Clojure have named parameters?

12:48 blbrown: I forgot how to do this. if I have ... (let [l some-list] (some-func (fn [line] (append to list)) ... a list and then some func appends to the list. How would I append to the list. Is it just append

12:48 cmvkk: conj?

12:49 durka42: hipertracker: yes, all parameters are named, except in anonymous lambda fns #( ... )

12:49 cmvkk: ,(conj '(1 2 3) 4)

12:49 clojurebot: (4 1 2 3)

12:49 cmvkk: eh...

12:49 blbrown: hmm

12:49 cmvkk: ,(conj [1 2 3] 4)

12:49 clojurebot: [1 2 3 4]

12:50 kotarak: ,(concat (list 1 2 3) (list 4))

12:50 clojurebot: (1 2 3 4)

12:50 kotarak: The use of a vector with conj is probably what you want.

12:51 cmvkk: there's not a better way to append to a list than concat and wrapping the second argument in a list, I guess.

12:52 kotarak: I'm not aware of another way. If one needs to append, one should use a vector. If one needs easy adding at the end and simple retrieval at the front, one can use a PersistentQueue.

13:00 rlb: What position (if any) does clojure take wrt exceptions? For example, is it normal for clojure functions (built-in ones in particular) to throw exceptions?

13:02 durka42: exceptions are used kind of in the same way as java would

13:02 ,(distinct?)

13:02 clojurebot: java.lang.IllegalArgumentException: Wrong number of args passed to: core$distinct-QMARK-

13:02 durka42: ,(let [1 "one"] (prn "bad"))

13:02 clojurebot: java.lang.Exception: Unsupported binding form: 1

13:03 rlb: OK, in part, I just wanted to make sure I understood how defensive you need to be in cases where it might matter. Thanks.

13:03 durka42: there is also chouser's error-kit in contrib

13:03 rlb: Also, am I right in assuming that if you want your own type of exception, you would probably created it via gen-class, or is there some better way?

13:04 durka42: if you want it to have a distinct type that you can specify in a catch, then you have to gen-class it

13:04 rlb: OK, thanks.

13:18 lisppaste8: blbrown pasted "Mutate the vector" at http://paste.lisp.org/display/76622

13:19 cmvkk: if you want to mutate the vector

13:19 blbrown: I am assuming I need 'ref' I did this before but forgot the syntax. Is that the way to go

13:19 cmvkk: instead of [] use (atom []), and then instead of (conj vec-line ...) do (swap! vec-line conj ...)

13:20 you could use a ref too. but you're only working with one thing so either is okay.

13:20 blbrown: OK

13:20 cmvkk: oh and you have to use @vec-line to read it.

13:21 blbrown: I am using opennlp, pretty cool library and works flawlessly

13:22 cmvkk: what exactly is happening in that example, are you just looping through input, building that vec, then returning it?

13:22 because there's probably a way to do that without mutation...

13:23 blbrown: pretty much

13:23 cmvkk: you might be better off with loop/recur for rebinding then, rather than mutation. But it's hard to tell from this viewpoint whether that would make simpler syntax.

13:24 blbrown: maybe not even 'loop' but 'foreach' or whatever the call was

13:24 cmvkk: oh, yeah, for.

13:24 that's true too.

13:24 blbrown: I still have a Java/imperative programming style.. I will get there eventually

13:25 cmvkk: clojure is a good language for learning to code this way, because at least it makes you realize you're using mutation when you do.

13:26 blbrown: yea, it is pretty obvious isn't it

13:26 isnt like a = 3 , b = 4, a =3 in the imperative world

13:31 zakwilson: In Haskell, it's even more obvious. The mutation shows up in the type signature.

13:32 You *can* hide mutations in Clojure if you try. In Haskell, I'm pretty sure you can't.

13:32 cmvkk: i thought there wasn't mutation at all in haskell.

13:32 blbrown: and Erlang pretty much has no mutations

13:32 zakwilson: There's the State monad.

13:32 cmvkk: oh okay.

13:33 blbrown: zakwilson, I am assuming you worked with Haskell, it is certainly a different style from clojure. Do you like both haskell and clojure and is there one language you would use for X task and one for another

13:33 zakwilson: I have barely touched Haskell, but it really interests me.

13:34 From what I know of Haskell, Clojure is better for getting things done quickly, but Haskell is better for knowing things about a program's correctness.

13:34 ayrnieu: correctness with respect to types.

13:35 zakwilson: Yes, but but things have types in Haskell that don't really in other languages.

13:35 An IO action, for examlpe, shows up in the type signature of a function that uses it.

13:36 blbrown: zakwilson, good description

13:36 ayrnieu: does that seem like a good example of something you'd want to check for the sake of a correct program?

13:37 blbrown: I think there is a world for clojure, haskell, scala

13:37 s/world/architecture/g

13:37 zakwilson: In a formal sense, you could test that other ways if you're trying to prove a program correct.

13:38 In a real-world sense, I think it might reduce a programmer's error rate, but I haven't written anything non-trivial in Haskell, so I can't be sure about that.

13:39 rlb: Does clojure have a clever way to define a function that has only one optional argument, and where providing additional arguments is treated as an error? I know I can just check the rest list...

13:39 ayrnieu: rlb - define a multi-arity function.

13:39 blbrown: a good test framework is where you can prove correctness in a dynamic clojure world. But that takes a little extra effort, where I guess in haskell can be a little bit more automatic

13:39 hiredman: ~def max

13:39 rlb: ayrnieu: I saw that.

13:40 ayrnieu: (defn foo ([x] ...) ([x y] ...)) -- the lesser-arity function can supply the default value in a 'recursive' call to the greater-arity function.

13:40 zakwilson: blbrown: I think it's just a matter of where the effort goes. In Haskell, it's up front, when you're writing the program.

13:40 ayrnieu: zakwilson - correctness with types is 'up front', and continuous.

13:40 rlb: ayrnieu: ahh, I hadn't realized that the bindings allow them to call each other -- perfect.

13:40 (and quite nice)

13:41 zakwilson: ayrnieu: Yes. What I'm saying is that in Haskell, you have to spend more effort when you write the code, whereas with Clojure, the effort is moved to testing.

13:41 blbrown: and lets not leave scala out. If you are working with the jvm, I could see writing an architecture around clojure and scala. For example, I could see a web framework with clojure from fron end web application code and scala for database backend and server code

13:42 ayrnieu: zakwilson - you'll find that Haskell's type checking will be very useful indeed in Haskell, a language so opaque and horrible that you can hardly trust yourself to follow what your own idiomatically golfed code is doing. But to see how useful it is in general, just look at what you've been doing.

13:43 digash: blbrown: why do you see scala more useful for the backend then clojure?

13:43 zakwilson: I see ayrnieu isn't a big Haskell fan.

13:44 I've decided to learn it in an attempt to purify my mind after working on some really bad PHP. I don't know that I'll actually make a habit of using it.

13:45 blbrown: digash, kind of what zak was saying. You want correctness up front when writing more mission critical code. Like your server backend. But for the web application server pieces. Say in the MVC model, passing the data to the view form, you don't need for your entire application to be correct up front. Hope that makes sense

13:46 digash, this is just my ad-hoc take on where I would use a more dynamic language like clojure and where I would use something like scala or haskell

13:46 zakwilson: I think it's more a matter of... if you know exactly (or nearly) what you're going to make, more safety up-front is nice. If you don't, it may get in the way.

13:47 ayrnieu: zakwilson - that quote makes this more relevant: http://paste.lisp.org/display/75921

13:47 blbrown: and in a web environment, the more front end code, you are going to change what data gets displayed, what doesn't, etc, etc. Probably more often than the back-end layer.

13:48 ayrnieu, nice words of wisdom

13:54 zakwilson: ayrnieu: Very good, and I it illustrates well one of the things I think is wrong with Arc.

13:54 blbrown: oo, you messed with arc, im sorry

13:55 zakwilson: I've done PHP for money. Arc was nice by comparison.

13:55 blbrown: I think PHP, VBBasic?, Perl are competing for the ugliest languages

13:55 ayrnieu: blbrown - http://tnx.nl/php

13:56 zakwilson: http://paste.lisp.org/display/76132 <-- and that wasn't the worst of it

13:56 blbrown: hehe

13:57 zakwilson: I inherited a project that was PHP from a Ukranian sweatshop. I thought it would be quicker to refactor it than scrap it. I was wrong.

13:59 blbrown: actually, I did create a simple file upload system for my website. I guess for quick server side apps, it can be OK

13:59 http://botnode.com/ for example, here, I can update all of the content through my php application

14:00 hehe http://botnode.com/dev/app/octane_flowers.php

14:20 arohner: are there any rules about code that has dependencies on third party jars going into contrib?

14:20 kotarak: arohner: there is already eg. miglayout. That also needs a third-party jar....

14:22 arohner_: kotarak: thanks

14:23 kotarak: arohner_: however I'm in no way authoritative! :) So you should make sure with rhickey or chouser, I guess.

14:30 Chouser: clojure.parallel is itself optional, but requires a 3rd party jar if you want to use it.

14:30 and a couple of contrib libs require or can use a 3rd party jar

14:31 so I guess there's no rule against it. :-)

14:43 durka42: does this already exist in clojure?

14:43 (defmacro comp* [outer inner] `(fn [& args#] (apply ~outer (map ~inner args#))))

14:43 i.e. ((comp* = first) [1 2] [1 3]) => true

14:47 Chouser: I don't think so

14:47 rlb: Is there already any easy way to "tap" a java FileOutputStream (so you can have a clojure function operated on all the data passing through it)?

14:47 s/operated/operate/

14:49 I suppose I could just change the way I'm handling the file copy (and processing). I started off using nio (a ByteBuffer) because I was under the impression that it's substantially more efficient and this is going to handle a *lot* of data.

14:52 A simple thing to do would be to change it so that the code just presents the incoming and outgoing data as seqs of binary chunks. That'd be much easier to manipulate from clojure, but it would also (I assume) result in quite a bit of extra copying.

14:53 Chouser: durka42: another way: (defn comp*2 [a b] (comp (partial apply a) (partial map b)))

14:53 ((comp* = first) [[1 2] [1 3]])

14:54 durka42: ooh, that's better. less distance between thought and code

14:54 kotarak: and no macro :)

14:54 * durka42 wonder why the other was a macro

14:54 durka42: wonders*

14:58 hiredman: rlb: you can proxy OutputStream an have it close over your FileOutputstream

14:59 rlb: hiredman: and I'd selectively override its methods (assuming I understand both what you're saying and how clojure's methods work)?

14:59 hiredman: actually

15:00 I guess you could just proxy FileOutputstream

15:00 rlb: yes

15:00 durka42: define something as a macro, then try to redefine it as a non-tail-recursive function --> error

15:01 hiredman: ~java_interop?

15:01 clojurebot: Titim gan �ir� ort.

15:01 durka42: ~java interop is .

15:01 clojurebot: You don't have to tell me twice.

15:01 hiredman: ~java interop is http://clojure.org/java_interop

15:01 clojurebot: Ack. Ack.

15:04 rlb: hiredman: I think, at least for read-only ops, and if I want to keep from having to make more than one copy of the data, that a quick, simple solution might be to add something like (for-each-chunk [func file] ...). The func would be passed the (same) ByteBuffer after each read. Then func could just be composed of as many ops as desired.

15:04 hiredman: rlb: which ever way you want

15:04 blbrown: watch this

15:04 lightbot: I am sorry, I did not understand

15:05 blbrown: hello

15:05 lightbot: Hello, My name is light

15:05 blbrown: what is your name

15:05 lightbot: My master goes by the nick, blbrown

15:05 blbrown: thanks

15:05 lightbot: I am sorry, I did not understand

15:05 blbrown: do you want to play a game

15:05 lightbot: Yes David, I like to play games

15:05 blbrown: Hello my name is bob

15:05 lightbot: I am sorry, I did not understand

15:05 hiredman: having the bot react to ever line in the channel may get old fast in here

15:05 lightbot: I am sorry, I did not understand

15:05 blbrown: Hello my name is Bob

15:05 lightbot: My name is light

15:05 hiredman: you might want to take it to #clojurebot

15:05 rlb: hiredman: thanks, though, I'll keep your suggestion in mind, esp if I want transformational ops later.

15:06 blbrown: hiredman, yea, just testing, I have my natural language parser hooked up to it

15:06 hiredman: interesting

15:06 blbrown: that was verion 0

15:37 rlb: Does clojure have anything like scheme's case or cond syntax, or is that sort of thing normally handled by other means?

15:37 cmvkk: condp maybe

15:37 and cond

15:38 rlb: Sorry, I overlooked it in the docs -- thanks. I was looking on the doc page with if, do, etc...

15:47 Is tree-seq guaranteed to traverse the children in the order provided by the provided func by any chance?

15:47 * Raynes gives cmvkk a cookie.

15:47 rlb: "the children func"

15:48 At least in this case, that woud be very helpful.

15:48 gnuvince_: "the children func"... I'm sure this could get you arrested.

15:49 cmvkk: it seems like it would from the function def

15:53 rlb: cmvkk: it does seem pretty likely. Though since it's critical, I suppose I can insert some (obviously non-exhaustive) build tests, just to make sure it doesn't appear to change in future versions of clojure.

15:54 Raynes: Is there a function that takes 2 seqs and interweaves them like giving it (1,3,5,7) (2,4,6,8) would make (1,2,3,4,5,6,7,8)?

15:54 cmvkk: or since the def is only 5 lines long anyway, you could just copy it into your own source and control it that way.

15:54 interleave

15:54 Raynes: Hawt thanks.

15:54 cmvkk: ,(interleave [1 3 5 7] [2 4 6 8])

15:54 clojurebot: (1 2 3 4 5 6 7 8)

15:54 rlb: cmvkk: true -- I was thinking about that.

15:55 cmvkk: I should probably check out the clojure source.

15:57 cmvkk: ~def tree-seq

15:59 Raynes: (defn children-func [num names] (apply hash-map (interleave num names))) <--Children function.

16:00 durka42: bah i'm sorry for all the bouncing

16:00 sketchy w-fi

16:00 wi-fi

16:08 djkthx: hmm

16:09 im getting a strange error

16:09 when i start emacs

16:09 An error has occurred while loading `/Users/ynadji/.emacs':

16:09 File error: Cannot open load file, clojure-auto

16:09 but i have the path to clojure-mode added in my ~/.emacs

16:09 it's new after i switched to the google code clojure

16:11 nevermind

16:11 got it working

16:19 rlb: Does java have anything like (.isLink file) -- or more specifically, a (perhaps platform specific) way to get essentially all the information about a file (is it a socket, character device, etc...)?

16:21 Wow, so far, it looks like not (dating back to even 2001). If so, that's surprising... (to put it mildly).

16:23 p_l: rlb: by creating a cross-platform library, you either do it all-inclusive or lowest common denominator. Java had gone for the latter.

16:23 Common Lisp's pathname system is example of the former :)

16:24 rlb: OK, though if that's true, then I either just can't write the app I was working on in clojure, or I'll have to call out to a C or python helper application.

16:24 ...and if so, that's really too bad.

16:25 I suppose python might be the most portable thing.

16:29 Of course then the first FAQ entry will be "Q: why didn't you just write it all in python."

16:31 hiredman: http://www.idiom.com/~zilla/Xfiles/javasymlinks.html

16:31 rlb: hiredman: yeah, that's *very* disappointing.

16:32 I need everything, "is it a special file, is it a character device, what's the major and minor for the device, etc.".

16:32 (on unix at least)

16:32 I may need to re-think.

16:32 p_l: rlb: Check if there's low-level OS support library

16:33 rlb: p_l: right -- I'm going to look around a bit more.

16:34 p_l: I'm also starting to wonder if I might be able to just create something myself via JNI (or whatever), if necessary.

16:34 p_l: rlb: You might want to look at swig, then

16:35 I just lost a night playing with it :)

16:35 rlb: p_l: I have. I've used it for that before, though I may also want to see just how hard it would be to do it without the added dependency.

16:35 p_l: heh

16:36 just generate the bindings and you probably wouldn't need swig anymore, except maybe as compile-time dependency

16:36 rlb: I wonder if it would be feasible/useful to create some kind of clojure support for JNI wrappers.

16:38 I suppose messing with JNI directly is probably one way to figure that out.

16:38 cp2: rlb: you would just need a normal java class with native method definitions

16:38 you can do the rest from clojure

16:39 rlb: cp2: I was more thinking of some way to do something like what swig does, but from clojure. Perhaps not worthwhile, but i was just wondering...

16:39 cp2: yeah, i dont really know

16:39 AWizzArd: rlb: I think there is all you want. Check out http://openbook.galileodesign.de/javainsel8/javainsel_14_001.htm

16:39 This is in german, but anyway, just read the code and check the output

16:40 Listing 14.2 ShellFolderDemo.java shows how you find out if something is a link

16:42 hiredman: AWizzArd: he wants to be able to tell if a file is a character device

16:42 dreish: I haven't tried it, but jtux looks like a good general solution.

16:43 It provides access to all the POSIX syscalls.

16:43 abrooks: rlb: I posted a JNI example a while back... let me find it.

16:43 er..

16:43 JNA

16:43 rlb: dreish: haven't tried what?

16:44 dreish: rlb: jtux

16:44 abrooks: rlb: http://groups.google.com/group/clojure/browse_thread/thread/77e626c5440bf1a0

16:44 rlb: dreish: oh, right.

16:44 abrooks: dreish: jtux seems mostly dead.

16:44 dreish: abrooks: Maybe they got it right 3 years ago and haven't had anything to fix. ;-)

16:45 rlb: abrooks: ahh, so jna is java libffi-ish?

16:45 (I think I knew that...)

16:46 abrooks: dreish: Possibly, but my experiences with software say "No." ;-D

16:46 rlb: Yes.

16:46 dreish: More recently-updated: Posix for Java at http://www.bmsi.com/java/posix/package.html

16:46 durka42: Jtux supplies two non-standard functions, jaddr_to_seg and jaddr_from_seg to copy data between pointers represented as longs and Java byte arrays.

16:46 uh oh - pointers for java

16:47 abrooks: dreish: Ah, that's cool. Thanks for the link.

16:47 cp2: durka42: there is already somethign similar to that in the jdk

16:47 the class name is Unsafe

16:48 and lets you set/get data based on memory address

16:48 its one of those evil hidden classes :)

16:49 ezbake fed trials

16:49 rlb: dreish: ahh, ok, that's interesting, and at least judging by the file mod times, it looks active.

16:50 Thanks all -- I think I'll look in to java posix a bit further. If that works out, I'll just plan to help the upstream there.

17:10 dreish: that was easy, and so far, it appears to work. It also doesn't look like it would be difficult to extend.

17:11 excellent.

17:11 dreish: rlb: Thanks, I'm glad to hear it. I think I'll want to use it too at some point.

17:11 This was the one at bmsi.com?

17:11 rlb: dreish: yes.

17:14 Hmm -- wonder about adding a debian libposix-java package. I suppose for now if it works out, I'll probably just plan to include it, but later...

18:14 arohner: clojurebot: paste

18:14 clojurebot: lisppaste8, url

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

18:14 Chouser: heh

18:34 harry__: /past

18:39 rajarshi: Hi, a lisp newbie here and I had a question regarding loop, When using loop and recur to build up a list, how do I return the result of the last iteration? I'm always getting nil

18:41 cmvkk: (if (end-of-loop) result (recur (add-to-result) ...)) for example?

18:41 where you'd have a test for the end of the loop etc

18:41 rajarshi: cmvkk: ahh, missed the obvious solution. Thanks

18:56 Lau_of_DK: Good evening folk

18:56 All but the americans have gone to bed ?

18:57 keithb: All, what is the best way to pass key/value pairs to a function? Should I use (hash-map ...) to package them into a single map?

18:57 Or, is there some kind of syntactic sugar like in Ruby, where I can just pass key/value pairs literally?

18:57 Lau_of_DK: I'd say it depends on the purpose

18:58 cmvkk: arglists for functions can do all sorts of map restructuring if you want to do that

18:58 destructuring, more like

19:00 keithb: I'm writing a function that creates and returns a subclass of AbstractAction. I'd like to be able to be able to pass key/value pairs for its properties (tooltip, accelerator key, etc.) into this function.

19:00 There are several of these options, and I don't want to hard code any of them.

19:03 Lau_of_DK: I'd go with one hash-map

19:05 hiredman: clojurebot: destructuring?

19:05 clojurebot: destructuring is http://clojure.org/special_forms#let

19:05 keithb: Lau_of_DK: Thanks. It is a pretty clean way to go.

19:08 Lau_of_DK: Yea I think so

19:16 digash: i see in the gen-class doc that if i add to a signature a #^{:static true} it should generate it as static, but it does not

19:17 anybody has any example with static generation?

19:18 mgarriss: if i have a list of maps how do i increment some key within each map and return the coll? example: (foobar ({:x 0} {:x 0} {:x 0})) ; => ({:x 0} {:x 1} {:x 2})

19:21 cmvkk: so every map has 0 as the value of the key already?

19:21 mgarriss: each starts with :x set to 0

19:22 cmvkk: (map (fn [mp nv] (assoc mp :x nv)) map-list (range (count map-list)))

19:23 you're mapping over each map, and applying the value of an incrementing number to some specific key.

19:24 mgarriss: thx. new to clojure, this is still hard to understand

19:25 gnuvince_: ,(map #(update-in %2 [:x] %1) (map #(fn [x] (+ x %)) (range 3)) [{:x 0} {:x 0} {:x 0}])

19:25 clojurebot: ({:x 0} {:x 1} {:x 2})

19:28 cmvkk: yeah, that's more general than mine. It'll add an incrementing number to the value of :x whether it starts with 0 or not.

19:29 gnuvince_: Yours is less horrible though :)

19:29 cmvkk: whenever i try to type 'closures' now, i always accidentally type 'clojures'

19:29 gnuvince_: I have a map with an anonymous function to generate an anonymous function ;)

19:30 cmvkk: tell me about it.

19:31 hiredman: I wish rhickey would commit something

19:31 mgarriss: now i get it, i didn't realize that map could take multiple collections

19:31 cmvkk: yep. the number of collections is equal to the number of arguments in the map function.

19:32 gnuvince_: hiredman: like what?

19:32 mgarriss: yeah

19:32 hiredman: anything, I want to see if clojurebot's svn log -> twitter bit is working

19:32 gnuvince_: hiredman: don't you have mock objects to test that? *wink*

19:32 cmvkk: i was about to say...

19:33 real world testing is hard, you're supposed to be simulating this stuff.

19:33 replaca: Q: Is replicate being dropped in favor of repeat

19:33 ?

19:34 gnuvince_: mgarriss: Clojure has only map which can work with a variable number of arguments. If you know Haskell, you probably know zipWith through zipWith8

19:34 hiredman: I have dones some tests, and they worked

19:34 but I will not be sure it works until it is doing what I want it to do

19:36 cmvkk: replaca: they do seem to do the same thing. isn't it sad? replicate is the function closest in name to your handle.

19:37 replaca: cmvkk: I don't think repeat used to be there, and I thought I saw some comment that made me think that Rich was changing it over, but I was working on something else. I like repeat better, my handle aside. :-)

19:37 lisppaste8: keithb pasted "Maps" at http://paste.lisp.org/display/76643

19:38 keithb_: I guess it's a little simpler to specify the { } literal ArrayMap rather than (hash-map ...), all other things being equal, and for a very small map?

19:39 hiredman: ,(class {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9 :i 10 :k 11 :l 12 :m 13 :n 14})

19:39 clojurebot: clojure.lang.PersistentHashMap

19:40 ayrnieu: ,(take 5 (repeatedly #(repeat 2 (rand))

19:40 clojurebot: EOF while reading

19:40 hiredman: I think after nine items arraymaps are auto magically turned into hashmaps

19:40 ayrnieu: so I prefer 'repeat' to 'replicate'.

19:43 keithb_: hiredman: Interesting, thanks.

19:43 replaca: ahh, issue 55: remove replicate in favor of repeat with multiple arities

19:44 hiredman: well, repeat already has replicates functionality, it just hasn't been removed

19:44 replaca: yeah, I'm just trying to future-proof my code right now, so I guess I should remove all the replicates

19:45 ayrnieu: wishful thinking :-)

19:46 replaca: well, yes, but in this case it would help :-)

19:46 I'm generally in the midst of adapting cl-format and my pretty printer to the "lazy" world, which is a big code walk anyway, so I'm getting anything I can along the way

19:50 digash: i've got it, was putting static in the wrong place

19:50 :methods [#^{:static true} [suite [] junit.framework.Test] is the right way

19:51 :methods [[#^{:static true} suite [] junit.framework.Test] ; not this way :)

20:01 lisppaste8: arohner pasted "defn-memoize" at http://paste.lisp.org/display/76644

20:01 * arohner http://paste.lisp.org/display/76644

20:01 arohner: is that a good idea?

20:02 is there a cleaner way to write that?

20:05 cmvkk: well, does that work?

20:05 arohner: it works

20:05 just looks like it could be prettier

20:05 hiredman: `(def ~name (memoize (fn ~@body))

20:05 cmvkk: there's that too.

20:06 your version will choke on docstrings maybe though

20:06 arohner: right.

20:06 ayrnieu: and for multiple-arity defns?

20:06 cmvkk: it'll work for that.

20:06 fns do that just like defn.

20:08 replaca: well docstrings would work with ^#{:doc "xxx..."}

20:08 arohner: yeah, but you're losing half the reason of having defn

20:08 replaca: but that's not fully defn-style

20:09 cmvkk: can defmulti take docstrings yet?

20:09 ah, it can.

20:09 ayrnieu: arohner - your verison is fine.

20:10 arohner: ayrnieu: thanks

20:14 since clojure is immutable, you can test to see if two arrays are equal just by comparing pointers, right?

20:14 replaca: no

20:14 objects aren't "interned"

20:15 so you can have [0 1 2] and [0 1 2] as two separate things

20:15 cmvkk: equality is defaulty by value.

20:15 identical? will work that way though...

20:18 replaca: you might be confused because some languages (Java, I think) use immutable strings and "intern" them so the same string will always be the same object. But that generally isn't true of immutable objects in other environments

20:21 ayrnieu: Lua and Pike do that.

20:21 hiredman: ,(= "foo" (String. "foo"))

20:21 clojurebot: true

20:23 ayrnieu: ,(identical? "foo" (String. "foo"))

20:23 clojurebot: false

22:44 brennanc: trying to figure out how to connect to mysql through clojure. I'm import clojure.contrib.sql and then did (with-connection {:user "root", :subname "localhost", :classname "com.mysql.jdbc.Driver", :subprotocol "mysql"} (println "test")) but it says "jaa.sql.SQLException no suitable driver"

22:44 it's in the classpath and I can do (Driver.) and it creates an instance fine so I'm not sure what the problem is. Any ideas?

22:45 Chouser: http://stackoverflow.com/questions/613929/how-do-i-connect-to-a-mysql-database-from-clojure

22:47 brennanc: thanks, will try that

22:47 Chouser: I think it's step 2 that you may be missing

22:47 the -D thing

22:48 brennanc: just tried it without step 2 and it seems to work

22:48 I had the subname as "localhost". I needed to set it to "//localhost" for it to work

22:48 Chouser: oh, ok

22:49 brennanc: really weird. never heard that term before and it's weird to require the // in front

22:49 oh well, easy enough, just gotta know that I guess

Logging service provided by n01se.net