#clojure log - Feb 06 2010

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

0:00 BrandonW: i have another question :) i don't understand the difference between commute and alter. what is the difference between restarting a transaction, and re-running your function with the newest value of the ref you are changing?

0:01 and if commute doesn't care about in order processing, but alter does: don't they both work such that whichever operation on the ref finishes first is the first one that succeeds in changing the ref? how is commute different from alter in terms of ordering?

0:03 alexyk: liebke: ping?

0:15 liebke: alexyk: hey

0:16 alexyk: liebke: is there a paper I could cite for Incanter? Otherwise I did this: http://paste.pocoo.org/show/174472/

0:17 liebke: alexyk: that looks fine, I'm looking forward to reading the paper.

0:17 alexyk: liebke: cool

0:23 JayM: hmm..possible to get out of an infinite loop in slime?

0:25 somnium: JayM: C-c C-c

0:27 JayM: somnium: aha, thanks

0:33 slyrus: evening

0:34 so... I see that clojure-contrib has switched over to maven. how do I use maven to build a clojure-contrib jar without downloading all sorts of crazy jars from god-knows-where?

0:45 alexyk: liebke: I have two lists, xs and ys, I feed to scatter-plot. How do I save them to disk to get them back readily to reproduce scatter-plot?

0:45 need to reload with your pdf option

0:46 liebke: alexyk: create a dataset from the two vectors and save it with the save function

0:47 (save (conj-cols xs ys) filename)

0:48 alexyk: ok

1:06 liebke: and how do I load it back and feed to scatter-plot again?

1:09 liebke: alexyk: (scatter-plot :col-0 :col-1 :data (incanter.io/read-dataset filename :header true))

1:10 alexyk: liebke: for some reason conj-cols wasn't available, I did (matrix [x y]) -- how do I read *that* back?

1:10 x and y are vectors of x's and y's

1:11 liebke: alexyk: you might have an old version. incanter.io/read-dataset works with saved matrices too

1:12 alexyk: in the same way? are x and y columns then?

1:12 liebke: alexyk: check the saved file though, x and y are probably rows the way you created the matrix

1:12 use trans to flip them

1:12 i recommend updating incanter too

1:13 alexyk: tmrw :)

1:13 (after the 3 am deadline)

1:13 is there a :row-0 etc selector?

1:13 liebke: what time is it where you are?

1:14 alexyk: 1:14 am

1:14 liebke: (sel :rows 0)

1:14 alexyk: ok

1:14 liebke: (sel mat :rows 0)

1:15 alexyk: ah, you're in my timezone, where are you?

1:15 alexyk: liebke: Dartmouth

1:15 liebke: ah

1:15 alexyk: think Moose

1:16 fatrow: hi. Is there a way to get a subsequence like a slice of python?

1:20 qed: exec("/bin/kill $blah_pid[0] 2>&1",$a,$b);

1:20 ^^what is happening here?

1:20 what is the 2>&1 is that just sh script?

1:20 im trying to understand that line

1:21 krumholt: fatrow, something like split-at?

1:21 ,(first (split-at 2 [1 2 3 4]))

1:21 clojurebot: (1 2)

1:21 krumholt: ,(second (split-at 2 [1 2 3 4]))

1:21 clojurebot: (3 4)

1:24 fatrow: krumholt: thank you.

1:29 krumholt: fatrow, or if you need more arbitrary splits you can use a combination of drop and drop-last

1:30 ,((fn [coll x y] (drop (dec x) (drop-last (- (count coll) y) coll))) [1 2 3 4 5 6 7 8] 3 5)

1:30 clojurebot: (3 4 5)

1:31 fatrow: krumholt: thanks. I want to get a subsequence like (xxx [1 2 3 4] 1 3) => [2 3]

1:32 krumholt: yes my last post will do exactly that

1:32 fatrow: krumholt: thank you.

1:33 krumholt: ok not exactly that it starts at index 1 not 0

1:37 fatrow: I guess subseq is this, but it is different.

1:39 krumholt: ,(subvec [1 2 3 4 5 6] 2 4)

1:39 clojurebot: [3 4]

1:42 fatrow: krumholt: oh, subvec is this. Is there a subvec for general sequence version ?

1:43 krumholt: fatrow, i am not sure. but it is not subseq :)

1:43 ,(subs '(1 2 3 4) 2 3)

1:43 clojurebot: java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to java.lang.String

1:44 krumholt: ,(subs "blub" 2 3)

1:44 clojurebot: "u"

2:28 fatrow: krumholt: I have solved it. thanks.

2:28 (defn slice [coll start & end] (let [len (count coll), start (max start 0),end (if (nil? end) len (min end len))] (take (- end start) (drop start coll))))

2:30 zab: Is it worth attempting to shoehorn an installation of Clojure on App Engine?

2:31 hiredman: you don't need to shoehorn

2:31 it's fairly painless

2:31 zab: what about loss of language features like concurrency?

2:32 hiredman: *shrug*

2:32 zab: hmm ok

2:33 im fairly new to the whole JVM thing, but will give it a shot. any good resources out there particularly suited to GAE?

2:33 hiredman: http://github.com/zitterbewegung/blank-appengine-clj

2:33 looks good but I have no experience with it

2:34 zab: nice thanks!

2:34 hiredman: I have http://github.com/hiredman/appengine-helper but I am not regularly working on it, and it is slowly bitrotting

2:35 there are some nice blog posts around

2:35 zab: yeah i've read most of them i think. they are all pretty old though.

2:37 hiredman: appengine-clj was junk last time I looked at it, which was many moons ago

2:37 I really like google's datastore

2:37 maps well to storing maps

2:39 I did two apps on appengine, really small facebook apps (maybe five users tops)

2:39 mostly just for my personal use

2:40 zab: ive built a couple of python GAE apps. i really like the model and pricing structure.

2:40 and i want to pick up a new language, and clojure looks really interesting.

2:40 ive never really dug into a lisp before.

2:41 hiredman: running clojure on the appengine does mean you have to monkey around with AOT compilation

2:42 at least for the servlet file

2:43 the gen-class stuff can be painful to work with

2:43 zab: is this in the clojure documentation, or is this JVM stuff? (like I said, new to JVM)

2:44 hiredman: it is under compilation

2:45 the java appengine follows some java webapp spec "servlets" so you need to generate a class with a stable name that the servlet stuff can talk to

3:52 Lewisham: hi all, Clojure newbie here. I'm trying to do a simple recursive movement through a list, and it's not going well :) I keep getting an NPE thrown out, and I'm not sure what I'm doing wrong. It's very basic! http://pastie.org/812186

3:52 I'm also not sure if I'm doing things the Clojure way

3:52 so any help would be appreciated

3:53 hiredman: you have an extra pair of parens

3:53 Lewisham: I do? I thought they all matched up :/

3:54 hiredman: yes

3:55 a form like (a b) is function application

3:55 you have ((println ...) ...)

3:56 Lewisham: oh, I see

3:56 I didn't need to wrap the second clause in parens

3:56 d'oh

3:57 hiredman: if takes two forms

3:58 http://clojure.org/special_forms#toc12

3:59 ,(reduce (comp inc first list) 0 '("one" "two" "three"))

3:59 clojurebot: 3

4:00 hiredman: ,(count '("one" "two" "three"))

4:00 clojurebot: 3

4:00 Intertricity: How close is ClojureCLR to binary?

4:01 hiredman: "close to binary"

4:01 Intertricity: and, how do you access a C# dictionary from it >.> or can you

4:01 well it's via compile only atm :P

4:01 hiredman: so?

4:02 what does that have to do with binary?

4:02 Lewisham: hiredman: thanks very much :) I got it to work with (do...)

4:02 I need to figure out how this recur form works though

4:02 Intertricity: hiredman, I'm assuming they'll make a binary for more public use when it's mature enough

4:02 hiredman: binary is a counting system using two digits

4:02 Intertricity: ohh, no I meant compiled already

4:03 drop in and go

4:04 hiredman: so you meant to ask "how close is ClojureCLR to being distributed already built?"

4:05 Intertricity: yes, sorry, that would be a better way to put it

4:07 hiredman: hard to say, I don't know how much of a community it has, and community feedback tends to drive releases

4:55 Lewisham: hi, sorry, another silly question :) is there a way I can have (count-words) initialize "bins" if it's nil? I've been Googling for things like "default arguments clojure" and it's returning some scary key based stuff that I don't yet understand! http://pastie.org/812204

4:58 lypanov: you could use the multiple function defn form

4:58 (defn blah ([x] first fun) ([x y) second fun))

4:59 Lewisham: oh, that's true

6:20 StartsWithK: (time (dotimes [i 100000] (keyword (str "x" i)))) -> "Elapsed time: 2495.639935 msecs", but (time (dotimes [i 100000] (clojure.lang.Keyword/intern (str "x" i)))) -> "Elapsed time: 357.043285 msecs"

6:20 why such a big difference?

6:21 it looks like keyword checks for Keyword instance, and it wastes time on that

6:39 Chousuke: StartsWithK: an instance check shouldn't take that long :/

6:39 StartsWithK: http://paste.pocoo.org/show/174527/ i am trying to speed up my json lib, and by using Keyword/intern i get something like 4x speedup in reader (words was slurped from cca 330kb json file)

6:40 lets see how it works on c.c.json

6:46 ~2x speedup in c.c.json when using Keyword/intern vs keyword

8:00 qed: morning gents

8:03 AWizzArd: Hallo qed

8:13 qed: AWizzArd: top 'o the mornin' to ya

8:13 AWizzArd: how goes clojure?

8:14 AWizzArd: Going good so far, today I will be hopefully finishing my db transactions as the underlying mechanism for manipulations.

8:14 qed: interesting -- i dont know what you're talking about :)

8:15 AWizzArd: how does it work

8:15 AWizzArd: The DB system I am writing in Clojure for Clojure.

8:15 qed: are you using the STM as your DB, or something more heavy duty?

8:15 AWizzArd: ahh, very cool

8:15 AWizzArd: I thought you mean this when you asked how it is going :-)

8:16 qed: ah, sorry :)

8:16 AWizzArd: Under the hood it does not use the STM, but the data structures rhickey implemented, which are amazingly powerful and useful for such work.

8:17 qed: so clojure's standard structures? vec/map/set/etc?

8:17 AWizzArd: Yes. Because they are persistent.

8:17 qed: AWizzArd: would it be reasonable to build a DB on top of the STM?

8:18 or rather a layer of DBness on top of the STM?

8:18 AWizzArd: I wanted to do that first. But the current dosync does not allow the use of "plugins". If you want to synchronize DB changes to disk it must happen in a dosync block.

8:18 qed: from what i gather about STMs in general -- they behave like databases, and I wondered if one could use that with some tinkering, as a production DB

8:19 AWizzArd: i see

8:19 AWizzArd: But a dosync should not contain side effects/io. Also for a DB one needs to do a guaranteed write to the disk, which will slow down each dosync and may trigger hundreds of unsatisfying retries.

8:20 qed: AWizzArd: yes my next question was about retries, but the i/o is another excellent point

8:21 i am desperate to have some more time with clojure -- i have been so busy with other things lately

8:22 AWizzArd: The real usefulness is that Clojures data structures are fully persistent, as in http://en.wikipedia.org/wiki/Persistent_data_structure

8:22 qed: *nod* yes

8:22 tries -- bagwell

8:23 AWizzArd: i was so...amazed...when i first learned about persistence in clojure

8:23 i knew nothing of persistence prior to that

8:24 shared structure -- versions of a structure, it's so elegant

8:36 * raek <3 if-let, destructuring and re-find

8:39 qed: so much stupid in PHP it's unbelievable

8:39 I really love this community

8:39 #php, that is

10:08 raek: how does relations work in clojure.set?

10:09 can someone show an example of how clojure.set/index is used?

10:25 ok, found something: http://www.mail-archive.com/clojure@googlegroups.com/msg17047.html

11:12 npoektop: hi! can anyone help me with compojure? It looks a really simple question, but i can't find the answer myself.

11:12 hi! how do i get content of a POST request? I can do defroutes with (POST "/:name" ...) or smth and get that name with (params :name). But how do i get the whole content?

11:20 LauJensen: npoektop: check out my blog, have a few examples

11:20 http://www.bestinclass.dk/index.php/2010/02/reddit-clone-in-10-minutes-and-91-lines-of-clojure/

11:20 This one is quite easy

11:25 npoektop: LauJensen: oh, i now i get it. (GET "/*" ...) and (params :*). Cool. Thank you.

11:25 LauJensen: np

11:38 Raynes: http://force7.de/nimrod/ Looked a little bit interesting until I found out it's written in FreePascal. What's up with that? :o

11:39 patrkris: LauJensen: Is the new front-end in a state where I can test it, or is it currently b0rken?

11:40 LauJensen: talking about clojureql, if you were wondering :)

11:40 kotarak: patrkris: not ywt

11:40 yet

11:41 patrkris: kotarak: Ok. I checked out the frontend-2.0 branch. I like the new stuff (also from what I can read on gitorious). I'm excited :)

11:41 kotarak: thanks :) let's see how it works out.

11:42 There are quirks, but there are also a lot of improvements

11:42 patrkris: kotarak: I saw that somewhere in the source code it says "Monad stuff". I've never understood monads, but I think I might go try to work on my understanding of it now.

11:42 kotarak: it uses now a state monad.

11:43 patrkris: kotarak: my impression is that frontend-2.0 keeps the promise of being more clojure-like instead of SQL-like

11:43 kotarak: good for boilerplate, bad for dynamics

11:43 patrkris: kotarak: yeah... I have really no idea what it is. I've asked one of the PhD-students at my university to explain it to me, which he hopefully will soon.

11:44 kotarak: I try to get away from sql, I have working fleetdb prototype

11:44 patrkris: but i'm amazed that even some of the more senior scientists at my department aren't able to explain monads

11:44 kotarak: patrkris: it is overrated

11:44 patrkris: monads are overrated?

11:44 Chousuke: patrkris: The most simplified description of monads I can think of is that they describe how to compose operations

11:45 kotarak: yes, they are not a silver bullet

11:45 * lypanov wonders why "not-empty" isn't called "not-empty?"

11:45 patrkris: Chousuke: yes, I've read that somewhere - but still ... :)

11:45 Chousuke: patrkris: so that two sequences of operations composed under a different monad have a different outcome.

11:45 patrkris: Chousuke: ah

11:45 AWizzArd: lypanov: because it can return the coll

11:45 ,(doc not-empty)

11:45 clojurebot: "([coll]); If coll is empty, returns nil, else coll"

11:46 kotarak: patrkris: eg. i have to introduce non-sensic redirections to make the monad stuff independent from the backend

11:46 lypanov: AWizzArd: ah, k. now it makes sense. thank you!

11:46 AWizzArd: It does not return true or false.

11:46 Chousuke: patrkris: this only applies to operations that can be "lifted" to the monad though. some operations might be such that they only work within a single monad :/

11:46 lypanov: still think its weird that "empty" is so different to "not-empty"

11:47 patrkris: Chousuke: Ok. Did you go through category theory to understand them?

11:47 kotarak: not-empty is a sister to seq

11:47 Chousuke: patrkris: nah.

11:47 patrkris: I've just read loads of monad tutorials. and I'm still not sure if I understand them

11:47 lypanov: (defn two-of-each [xs] (let [x (first xs)] (if (not-empty xs) [] (concat [x x] (recur (rest xs))) )))

11:47 Chousuke: patrkris: this is just my interpretation

11:48 lypanov: anyone have a clue why this isn't accepted? what does "recur must be in tail position" mean exactly?

11:48 patrkris: Chousuke: hehe, well that's what I've tried to do too, but probably not hard enough

11:48 lypanov: i guess i need a more specific form than this, i've used it a few other times without issue.

11:49 Chousuke: patrkris: I think the principles behind monads are simple enough, but it's so abstract that it's difficult to see how to apply it to a real problem :/

11:49 lypanov: ah... got it.

11:49 concat is in tail position?

11:49 Chousuke: lypanov: recur is in the tail position of the concat form, not the defn form :)

11:52 kotarak: lypanov: (defn two-of-each [coll] (mapcat (juxt identity identity) coll))

11:53 lypanov: ooo. identity is cute.

11:55 qed: Chousuke: you can have a recur without an explicit loop form

11:56 Chousuke: hm?

11:56 qed: gah i just reformatted -- it's in stuart's book

11:57 kotarak: fn also adds a "loop" point for recur

11:57 qed: kotarak: thank you

11:57 Chousuke: Did I say something that hinted otherwise? :/

11:57 qed: i think i mis-read -- sorry Chousuke

11:58 kotarak: Chousuke: maybe it was a question?

11:58 qed: i just saw recur .... not the defn form

11:58 which means! it's time for bed. night all

11:59 lypanov: heh. night qed :))

12:13 StartsWithK: how can i test is my pom.xml file correct without maven/lain/other build tools..

12:13 is there a validator tool?

12:13 and, how do i declare dependency on clojure 1.1-1.2-SNAPSHOT

12:16 kotarak: StartsWithK: [1.1,1.2-SNAPSHOT]

12:16 StartsWithK: do i declare my lib alpha/beta?

12:17 if it depends on 1.2 (alpha) shouldn't then that reflect my version too?

12:17 i can't be 'stabel' if i depend on something that isn't?

12:32 arkrost: hi! Can anyone explain how to use dotimes macro with several bindings?

12:37 the-kenny: arkrost: Looks like dotimes only support exactly one binding

12:42 AWizzArd: one can easily stack them, or use for

13:13 rhickey: did you hear/read from Mark Tarvers (teamed up with Carl Shapiro) effort to make the important parts of Qi available in such a way, that it can be ported to Clojure without too much work?

13:14 Message-ID: <37b52400-6e4f-4a15-8bd9-bb7b45ea8a40@14g2000yqp.googlegroups.com>

13:58 BrandonW: i have another question :) i don't understand the difference between commute and alter. what is the difference between restarting a transaction, and re-running your function with the newest value of the ref you are changing?

13:58 and if commute doesn't care about in order processing, but alter does: don't they both work such that whichever operation on the ref finishes first is the first one that succeeds in changing the ref? how is commute different from alter in terms of ordering?

14:08 LauJensen: You pretty much said it. Commute doesn't enforce strict ordering, so you need to work on operation which arent dependant on the order, for instance incrementing, alter does enforce strict ordering, so moving items from 1 datastructure to another will maintain integrity, ie. the order in which the items were listed in list #1

14:12 BrandonW: well, for example consider a chat application where a message log is being modified from multiple sources. the most recent message would appear at the top. i would consider that to be dependent upon ordering

14:13 however, i don't understand the difference between commute and alter there. in either case, whichever operation finishes the transaction first is the one that successfully modifies the message log

14:14 i don't understand what the difference between alter's need to restart the transaction if the value the ref is pointing at changes, versus commute's ability to just rerun the function without restarting the transaction (isn't that all the transaction is, just running the function on the most current value of the ref?)

14:18 zaphyr: but the restart may cause your transaction to decide it should not continue

14:19 BrandonW: ohhhhhhhhhhh

14:19 zaphyr: whereas with commute, it cannot fail

14:19 hiredman: eh?

14:20 zaphyr: chat logging is a bad example- imagine credit/debit transactions on a bank account, or similar

14:20 BrandonW: okay that is a much better example

14:20 zaphyr: hiredman: have i misunderstood the difference between commute/alter myself? :/

14:20 BrandonW: one transaction aims to debit $50, the other wants to debit $45, the account has $55 total

14:21 well

14:21 so you can't have validation or anyting preventing a commutative transaction from continuing?

14:23 ordering seems to be the main difference between alter & commute, but the order seems like it would stay the same no matter which function you use to modify the ref

14:23 hiredman: the credit/debit is better than logging because for stm examples it is best to have at least two refs

14:24 but it is not good enough because you are still doing addition and subtraction

14:24 which are communicative

14:24 zaphyr: hiredman: yeah. agreed :)

14:24 hiredman: LauJensen's example was pretty good but not fleshed out

14:25 if we have two refs, A and B, A points to [1 2 3] and B points to [4 5 6]

14:27 BrandonW: okay i think i understand now

14:27 i was thinking in terms of operations too simple (and coincidentally commutative)

14:27 Chousuke: "alter" is always the safe choice

14:27 hiredman: alter?

14:27 clojurebot: alter is always correct

14:28 BrandonW: so it is more along the lines of if you have several actions that have to be done in a certain order, you can start the action via several alters, but as long as yuo start them in order you know they will be finished in order

14:28 Chousuke: you can use commute if you notice that you're getting unnecessary restarts :)

14:28 BrandonW: whereas if you use commute, even if you start them in order, the 3rd one might finish first, then the 5th, then the first, etc.

14:29 okay i definitely understand now... alter seems closer to synchronous, because if you have several actions, the quick ones might be much easier to execute, but they are at the end. so you would have to finish the first ones (which might be longer running) first

14:29 Chousuke: I'm not sure if that's quite right.

14:30 zaphyr: specifically commute works only for commutative operations- that is X op Y == Y op X

14:30 no matter what order you evaluate a sequence of commutative operations, the result will always be the same

14:30 BrandonW: well, consider a problem where you have several operations that have to be done in order. the first operation takes X time to complete, the 2nd takes x+1, the third takes x+2

14:30 hiredman: BrandonW: if they are running concurrently the short transactions will complete and cause the longer running ones to restart

14:30 BrandonW: so all the actions try to execute at first, but every one but the first theoretically will complete before the first, but they would all have to restart because the first one wasn't done yet

14:31 and then again with teh 2nd, then again with the third

14:31 hiredman: STM is not a lock

14:31 Chousuke: no, the first one would restart if the second finishes first :/

14:32 BrandonW: okay i still don't understand the ordering concept then :(

14:32 hiredman: clojurebot: the STM is not a lock

14:32 clojurebot: In Ordnung

14:32 hiredman: clojurebot: stm?

14:32 clojurebot: No entiendo

14:32 zaphyr: xD

14:32 hiredman: :(

14:32 clojurebot: the stm

14:32 clojurebot: the STM is not a lock

14:32 Chousuke: transactions are not ordered, but the operations within one transaction are

14:32 BrandonW: oh ok

14:32 Chousuke: unless you use commute, in which case it eases up the requirements a bit

14:33 BrandonW: but the operations inside a commute transaction aren't ordered

14:33 or aren't *necessarily* ordered

14:34 but then if the only thing that changes is the potential order of expressions in a transaction, how can that improve performance in commute vs alter?

14:34 Chousuke: say transaction A modified X with alter and Y with commute, and B modifies Y with commute; both start at the same time, but B finishes first; now, A doesn't need to restart.

14:34 that's as far as I understand it. I hope I'm getting it right. :/

14:35 of course, if A is designed so that it actually depends on the final value of Y, then it contains a bug :)

14:37 BrandonW: ohhhhhhhhhhhhhh okay

14:37 that just made it click

14:38 i'm was thinking of transactions as a single function call

14:38 but you can have multiple alters/commutes at once

14:38 zaphyr: ah. yeah. don't do that :)

14:38 hiredman: BrandonW: right

14:38 zaphyr: yeah, this is happening all at once, you really don't know what's coming in next

14:38 Chousuke: then there is ensure, which you need to use if you read Y and alter X based on the read value; if you just used deref, something else might use commute on Y and the altering of X would be done with an "old" value :/

14:38 BrandonW: now i understand what the programming clojure book was saying when commute only requires the commut call to be re-executed, versus alter which needs to restart the entire transaction (which could contain a lot of other function calls)

14:39 ensure hmm

14:40 i think that is going to be one of the difficulties after i finish the programming clojure book: finding out all the new additions since the book (or things the book didn't mention)

14:40 Chousuke: heh.

14:40 you need to get chouser and fogus' book :P

14:40 lypanov: yeah, today.

14:41 BrandonW: is that the new one coming out soon?

14:41 lypanov: they areon 37% discount.

14:41 um. i'm a java / ruby head. alien to this strange () filled world.

14:41 zaphyr: hmm, yeah i read that- does that include dead tree versions when they're complete?

14:41 lypanov: any one think guice is needed if you have the various alt project abstractions lisp provides?

14:42 * lypanov is trying to figure out if he should buy a cute looking manning DI book

14:43 BrandonW: which book is written by chouser and fogus?

14:43 lypanov: BrandonW: http://www.manning.com/fogus/

14:43 BrandonW: i only see Practical Clojure by Luke Vanderhart in addition to programming clojure

14:43 hiredman: lypanov: definitely not

14:43 BrandonW: awesome, i'll bookmark that for later

14:44 lypanov: and http://www.manning.com/rathore/ (which i have mainly as it looks neat to learn style from)

14:44 hiredman: figured as much :)

14:44 BrandonW: clojure seems like it is speeding up

14:44 lypanov: and a good book on unit testing, universally applicable?

14:44 * lypanov not a big fan of unit testing, prefers good integration tests and very few unit tests

14:45 * lypanov can really see why unit testing would be insanely easy with lisp however, its such a mess with other langs

14:45 lypanov: s/lisp/clojure/

14:45 zaphyr: lypanov: i quite liked http://www.amazon.co.uk/Test-Driven-Acceptance-Java-Developers/dp/1932394850, ymmv

14:45 Raynes: It's obvious that Joy is going to be awesome, but it's not complete enough for one to learn off of yet.

14:46 BrandonW: 3 new books coming in the next 10 months

14:46 unit testing seems to lend itself to functional programming in general

14:47 okay i gotta go

14:47 thanks for all the help re: commute vs alter :)

14:48 lypanov: zaphyr: ah, koskela ... interesting: http://www.manning.com/koskela2/

14:49 zaphyr: hmm, looks like that one seems much more language agnostic

14:49 lypanov: reading through the chapter list makes me thing "oh, not needed with lisp" tbh

14:49 s/thing/think/

14:50 maybe i'll just wait on the chapters in clojure in action for the moment

14:50 part ii has tdd stuff

14:50 zaphyr: yeah, to a degree. the nice thing about test harnesses, primarily, is that when you want to change a big huge system, you can run all the tests to make sure you didn't break something far far away

14:51 lypanov: i'm already a tdd fan, just missing some of the tricks needed for java. but by the looks of it, half of the pain isn't even seen when using clojure.

14:52 zaphyr: ahh, right, yeah. clojure makes a lot of the pain irrelevant

14:52 Chousuke: one tends to write a function and then test it immediately afterwards until it works :P

14:52 lypanov: Chousuke: *nod*

14:52 on that topic,

14:53 do you guys have tricks for printf debugging of complex things?

14:53 inserting a print randomly in ruby is just trivial, but it gets quite complicated in clojure.

14:53 hiredman: doto

14:53 Chousuke: complicated? :/

14:53 hiredman: and use prn

14:53 not println

14:54 lypanov: doh! didn't know about prn. thx hiredman!

14:54 hiredman: ,(doto 1 prn)

14:54 clojurebot: 1

14:54 1

14:54 lypanov: i'm still half way through core. doing the projecteuler stuffs.

14:54 Chousuke: I suppose instead of random printfs you should use a proper logging macro so that they can be easily disabled when you don't want to see debugging output

14:54 hiredman: Chousuke: pfffft

14:55 lypanov: Chousuke: its just for in repl debugging.

14:55 hiredman: what are you? some kind of professional?

14:56 lypanov: ooo. comp is neat.

14:57 hiredman: I really should figure out logging, I did some on appengine, prn doesn't work there

14:59 lypanov: hiredman: ah, doto ... prn is cute. thank you. just what i needed.

15:03 arohner: in clojure, strings are interned, so = compares by pointers, rather than strcmp, right?

15:04 I'm wondering if I'll get in trouble by using strings as keys in a map

15:05 Raynes: ,(keyword "hai")

15:05 clojurebot: :hai

15:05 arohner: ,(keyword "I am a string with spaces")

15:05 clojurebot: :I am a string with spaces

15:05 arohner: shrug. that works too

15:06 hiredman: don't do that

15:06 just use strings

15:06 Raynes: arohner: I wasn't answering your question.

15:06 :p

15:06 I was just checking out the keyword function.

15:06 Use strings.

15:07 AWizzArd: Raynes: I brought this issue up a few days ago.

15:07 ,{:a 1, :a 2}

15:07 clojurebot: {:a 1, :a 2}

15:07 Raynes: AWizzArd: I know.

15:07 zaphyr: ?! how?

15:08 Raynes: zaphyr: Magic.

15:08 zaphyr: broken magic XD

15:08 Raynes: Indeed.

15:08 AWizzArd: ,(hash-map :a 1, :a 2)

15:08 clojurebot: {:a 2}

15:09 billsmithaustin: ,(class {:a 1, :a 2})

15:10 zaphyr: :(

15:10 ,(keys { :a 1 :a 2 :a 3 })

15:10 clojurebot: (:a :a :a)

15:11 zaphyr: ,(conj { :a 1 :a 2 :a 3} { :a 4 })

15:11 clojurebot: {:a 4, :a 2, :a 3}

15:11 zaphyr: :S

15:13 Is it a bug in the reader? or nastier?

15:14 hiredman: arraylist doesn't check keys

15:14 ~ticket #87

15:14 clojurebot: {:url http://tinyurl.com/y92lmv8, :summary "GC Issue 83: PersistentArrayMap trust the reader (map literals) too much", :status :test, :priority :low, :created-on "2009-06-17T20:36:09+00:00"}

15:14 hiredman: there is a patch :P

15:15 zaphyr: aha. phew. i had a moment there. rhicky: accept this patch please :D

15:18 hiredman: actually, the patch only adds guards to the reader, I suppose it should also add guards to arraymap

15:19 zaphyr: hmm. probably. how much of a hit is it?

15:19 performance wise?

15:19 (correctness should probably be favored over performance here though, imo)

15:21 hiredman: the patch creates a hashset of the keys everytime a map literal is read

15:22 zaphyr: yeah, one time reader costs probably don't hurt much at all

15:22 hiredman: and it throws an exception if you try to read a map with duplicate keys

15:23 zaphyr: :)

16:10 Scriptor: hey everyone

16:23 npoektop: i still can't get parameters of a POST http method with compojure. Can anyone help me? http://pastebin.com/d6e4b5cd6

16:26 hiredman: "/:*"

16:26 if I recall

16:29 zaphyr: hmm. I have found myself wrapping awt with multimethods and macros. That isn't inherantly a bad thing is it? It makes things much more lispy :)

16:30 hiredman: why are you using awt?

16:30 zaphyr: well, the Graphics2D part of awt

16:30 swing for UI components, naturally

16:30 hiredman: just making sure

16:31 zaphyr: and you rightly should :)

16:31 things like (with-graphics g (draw-line 50 50 200 200))

16:32 binding g to a private fluid var *g*

16:34 npoektop: hiredman: no, "/:*" doesn't work

17:22 lypanov: i don't get if-let...

17:23 kotarak: ,(if-let [x 5] x 6)

17:23 clojurebot: 5

17:23 kotarak: ,(if-let [x nil] x 6)

17:23 clojurebot: 6

17:23 kotarak: ,(if-let [x false] x 6)

17:23 clojurebot: 6

17:23 kotarak: ,(if-let [x true] x 6)

17:23 clojurebot: true

17:24 lypanov: i keep getting the equiv of "unable to resolve x in this context"

17:25 kotarak: lypanov: code?

17:25 lypanov: i'm too ashamed to paste :P

17:25 AWizzArd: ;-)

17:25 kotarak: lypanov: you shouldn't be

17:26 lypanov: k... *shame*

17:26 https://gist.github.com/c6791d30086488f4335c

17:26 kotarak: The binding is only in the true branch of the if.

17:27 lypanov: line 19. has an if-let form. 'm getting the error: java.lang.Exception: Unable to resolve symbol: rest2-primes in this context (NO_SOURCE_FILE:385)

17:27 ah! doh

17:27 kotarak: After the seq call you know it's nil.

17:27 in the else branch, that is

17:27 lypanov: good point... how on earth did this code work.

17:28 thinking in clojure is teh hard

17:28 kotarak: *shrug* Schroedingbug

17:28 lypanov: it wasn't used anyway, so the nil just got ignored previously

17:29 kotarak: lypanov: no, it's not. Clojure is veeery consistent. cf. alter, commute, swap!, update-in, .... Know one, you know the others.

17:29 lypanov: thank you :)

17:29 kotarak: agreed, but when you're 3 days in... and you're trying to solve problems that you'd find hard in any lang. its teh hard. :P

17:29 kotarak: ok. That's true. :)

17:37 AWizzArd: lypanov: already some hours ago i saw you talking.. were you learning all those hours Clojure?

17:38 lypanov: AWizzArd: and watching crap tv :P

17:38 but yeah, crap tv takes around 5% in my brain-top

17:39 AWizzArd: maybe resting can be nice from time to time :)

17:39 lypanov: AWizzArd: my wife will force me to do that eventually.

17:39 :P

17:39 AWizzArd: great

17:39 lypanov: anyway. inbetween coding i'm watching the "clojure for lisp programmers" video at double speed.

17:40 AWizzArd: yes

17:40 * lypanov doesn't actually know lisp

17:40 lypanov: okay. getting closer to not sucking: https://gist.github.com/c6791d30086488f4335c

17:48 Mec: In emacs, is there a way to get things to output to the repl instead of *inferior-lisp* or *slime-events*?

17:49 the-kenny: Mec: I think there was some variable in emacs to accomplish that

17:53 ha!

17:53 AWizzArd: Ja?

17:53 the-kenny: Mec: Try C-h f slime-redirect-inferior-output

17:54 arohner: I have a list, I want to map over it, but I want each call to give me two adjacent elements. Is there a function that does that?

17:55 i.e. (map* f (range 5)) would call (f 0 1) (f 1 2) (f 2 3) ...

17:55 the-kenny: arohner: destructuring and (partition)

17:55 zaphyr: ,(partition 2 1 [1 2 3 4 5 6])

17:55 clojurebot: ((1 2) (2 3) (3 4) (4 5) (5 6))

17:55 the-kenny: ,(doc partition)

17:55 clojurebot: "([n coll] [n step coll] [n step pad coll]); Returns a lazy sequence of lists of n items each, at offsets step apart. If step is not supplied, defaults to n, i.e. the partitions do not overlap. If a pad collection is supplied, use its elements as necessary to complete last partition upto n items. In case there are not enough padding elements, return a partition with less than n items."

17:55 arohner: thanks!

17:59 Mec: the-kenny: thanks, that's exactly what I wanted

18:02 lypanov: ok.

18:02 the-kenny: Mec: You're welcome :)

18:02 lypanov: can anyone with a few minutes go over https://gist.github.com/c6791d30086488f4335c and tell me why it sucks?

18:03 (other than the fact that lcm can be done way way easier ;) )

18:03 Mec: hmm that didnt redirect all, is there a way to redirect output from evaluating an expression to the repl instead of just the little line at the bottom?

18:04 kotarak: lypanov: something more general: use (next ...) instead of (seq (rest ...))

18:06 lypanov: cute. thank you.

18:08 zaphyr: i need to dispatch on my defstructs and general classes- am i doing this right? http://paste.lisp.org/display/94500

18:10 Mec: I think you can replace tag-or-class with just type

18:10 zaphyr: aha, thanks :)

18:10 Mec: maybe not

18:11 zaphyr: nope. PersistantStructMap :)

18:13 lypanov: is there any other way to do multi return value than destructuring in the caller?

18:13 technomancy: lypanov: how else would you?

18:13 to return multiple values, you'd have to return a collection type

18:14 lypanov: clomagic? :P no idea.

18:14 zaphyr: tchnomancy: call-with-values (scheme) multiple-value-let (common lisp)

18:14 but clojure doesn't support that behaviour

18:14 technomancy: zaphyr: what does that mean?

18:15 the-kenny: lypanov: It's easy to implement with metadata, but they're bound to types which support metadata then

18:15 technomancy: I mean, if multiple values are returned, it must be a collection type, right?

18:15 zaphyr: you cease to have functions that return

18:15 the-kenny: technomancy: Common Lisp has "Optional Return Values". There's one main-value and optional, additional values which you can access with multiple-value-bind

18:16 zaphyr: ahh, multiple-value-bind, i thought that was wrong =]

18:16 lypanov: now i understand why clojure is a good lang for me to learn ;)

18:16 last time i started cl i almost fainted.

18:16 zaphyr: technomancy, effectively (inside the compiler) a function calls another function with the arguments returned by values

18:17 technomancy: and that's considered useful?

18:17 * lypanov gets the idea that thats what he's really meant to be doing

18:17 zaphyr: the net result is you don't end up boxing up anything to get multiple returns

18:17 the-kenny: technomancy: It's useful.

18:17 It's possible if the value returned by let is nil or it wasn't found, without a special value for "not found"

18:18 lypanov: okay. taking AWizzArd's advice and taking a much needed sake drinking break.

18:18 technomancy: so it reduces the need for things like containts?

18:18 *contains?

18:19 zaphyr: and partition can just return two values, rather than a list of two values

18:36 clojure.lang.PersistentBitVector. want!

18:37 hiredman: damn

18:37 (+ 1 2) in the repl doesn't call Expr.parse

18:37 clojurebot: 3

18:37 hiredman: clojurebot: byte me

18:37 clojurebot: My mother? I'll tell you about my mother

18:42 hiredman: I'm thinking #^{:primitive true} (+ (float 1) (float 2)) is nicer than (jop + (float 1) (float 2))

18:44 zaphyr: could there not be f+ f- f* ... i+ i- i* with automatic coercions?

18:45 hiredman: easier to dispatch (and better) to dispatch on type

18:45 easier (and better) to dispatch on type

18:46 zaphyr: hmm, yeah i suppose so. maybe just add a float reader format #^{:primitive true} (+ 1.0f 2.0f)

18:47 hiredman: zaphyr: but then what about non-literals?

18:47 zaphyr: use float still :)

18:47 i'm just thinking about populating a matrix full of float literals. ick.

18:47 hiredman: anyway, in my conception this is not for users

18:48 this is at the bottom of the numbers dispatch stuff that has already determined the types of all the numbers

18:48 zaphyr: ah, right

18:58 gstratton: Hi, I can't figure out why this doesn't work: (for [i (map vector '(float int int) '(0.5 2 4))] (apply (first i) (rest i)))

18:58 I want to apply a list of args to a list of single-valued functions

18:59 I'm sure there are multiple shorter ways which do work, but I'm stumped finding them

18:59 hiredman: that is a pointless thing to do

19:00 you are casting to primives, and then sticking the result into a collection that does not support primitives

19:00 so they are boxed all over

19:05 zaphyr: gstratton: to make the code work, you might want to try [float int int] instead of '(float int int)

19:06 but as hiredman says, you'll be casting to integers and wrapping them back into boxed Integers, so its probably not the best thing to do

19:07 gstratton: Okay, thanks, I'm reading up on boxing now.

19:08 zaphyr: i'm not sure what the effect of calling a symbol as a function is, but that's what you were doing

19:09 gstratton: zaphyr: Oh, I see, thanks

19:09 zaphyr: ,('foobar 3)

19:09 clojurebot: nil

19:09 hiredman: ,('f {'f 1})

19:09 clojurebot: 1

19:10 zaphyr: ahhh, so like keywords

19:10 thanks :)

19:10 hiredman: yes

19:46 zaphyr: hmm, if i implement a version of drop-while which works from the end for vectors, would that still be horrible?

19:47 i think that removing from the end of a vector via subvec would be O(1), so it would be fine?

19:59 wilig: https://gist.github.com/2574d3bba9a9540c1bb8 My first attempt at validation. Constructive criticism would be most welcome.

20:03 hiredman: :D

20:04 wilig: heh

20:04 zaphyr: you could filter with identity instead of #(not (nil? %))

20:05 hiredman: wilig: if you collapse each verification function into a single function, you can use a map instead of a vector of vectors

20:05 but I guess that has downsides as well

20:06 I have #^{:primitive true} (+ (double 1) (double 2)) compiling to a dadd :D

20:06 zaphyr: \o/

20:08 wilig: I'm so far over my head. Haven't even made it to the macro chapter in programming clojure yet. Having lots of fun though.

20:09 zaphyr: Could you use little words and explain filter with identity?

20:09 zaphyr: ,(filter identity [1 2 nil 3 4])

20:09 clojurebot: (1 2 3 4)

20:09 wilig: Ah!

20:09 zaphyr: ,(doc identity)

20:09 clojurebot: "([x]); Returns its argument."

20:10 wilig: Oh, thanks for showing me the light. Much better.

20:10 zaphyr: np

20:12 qed: wilig: ive been at clojure for a few months and i still feel the same way, learning so much fun stuff along the way though

20:12 clojure is like a supplementary CS education

20:12 wilig: I totally agree

20:13 I've always wanted to learn a bit of lisp, and I'm having the time of my life.

20:14 Hardest part is internalizing how much can be accomplished just by combining the core functions in various ways.

20:16 hiredman: user=> (expression-info (with-meta '(bit-shift-right (byte 10) (byte 1)) {:primitive true}))

20:16 {:class byte, :primitive? true}

20:16 zaphyr: :D

20:16 much win

20:17 hiredman: well, I still need to see if rich is interested in it

20:18 qed: wilig: i like to look at code ive written in other languages and adapt it to clojure -- it helps my brain a bit to see what i used to think of, and how to think of it in clojure

20:19 zaphyr: hiredman: is it generating java bytecodes, or calling static methods that do the work?

20:21 wilig: qed: actually that's a very good idea. I may have to try that. thanks.

20:22 hiredman: zaphyr: java bytecode

20:22 right now + and similar compile down to calls of static methods from Numbers.java

20:22 zaphyr: then I totally have a use for that. can't wait to play with it :)

20:23 hiredman: but this le you generate bytecode directly, trading off flexibility

20:23 lets

20:24 zaphyr: would be incredibly useful for DSLs I'd wager

20:24 hiredman: how do you figure?

20:24 DSLs usually seem to want more abstractions and indirection, not less

20:25 zaphyr: yeah, but say your language works only with ints and longs

20:25 and needs to go faster than unboxing into bigints

20:26 it looks like you could create a mini compiler for said language with that, if i understand you correctly

20:26 (potentially without requiring a clojure runtime)

20:26 hiredman: if you want to write a compiler you can use the asm library, just like clojure does

20:27 zaphyr: hmm. good point.

20:34 hiredman: but it might make this less painful, right? http://paste.lisp.org/display/94503

20:37 hiredman: I don't know

20:45 http://gist.github.com/297122

20:46 zaphyr: instruction 12 \o/ :)

20:46 i presume you only box everything back up at the very end

20:47 so there could be much hair in that function

20:47 hiredman: the compiler infrastructure takes care of that

20:47 it's pretty nice, .emit vs. .emitUnboxed

20:48 zaphyr: i like it

20:48 hiredman: in this case .emit calls .emitUnboxed and then does the boxing stuff

20:49 zaphyr: yeah. literally my only gripes are lack of primitive types in arguments/return, and inability to also inline that (for extreme performance win). copy-in-place optimization would probably make my vector math library faster than the java version...

20:50 hiredman: it's neat to see the locals clearing stuff aconst_null, astore_1

20:50 ,(doc definline)

20:50 clojurebot: "([name & decl]); Experimental - like defmacro, except defines a named function whose body is the expansion, calls to which may be expanded inline as if it were a macro. Cannot be used with variadic (&) args."

20:51 hiredman: I now rhickey is thinking/working on a primitive argument interface to fns

20:51 zaphyr: yeah, but i want an inline metadata to stuff on standard fns

20:52 although, definline does do the trick for now

20:52 just means i have lots more #'s in my code than i'd like

20:53 hiredman: clojurebot: performance

20:53 clojurebot: http://clojure.org/java_interop#toc46

20:57 zaphyr: yeah. actually it was unclear, do i need (int ...) around Float/floatToIntBits, given that that returns an int anyway? I'd imagine not

20:58 hiredman: I don't think so

20:59 zaphyr: figures. that and a bunch of vector math stuff was the first thing i wrote in clojure, and already it looks silly

21:00 Mec: In emacs, is there a way to redirect the output from lisp-eval-last-sexp to the repl instead of *messages*?

21:16 Lewisham: hi all, can anyone figure out how I would get this function to work? recur isn't the tail expression, but I can't seem to work out how to get it to be the last expression... http://pastie.org/812951

21:22 somnium: Lewisham: try writing it with reduce

21:22 Mec: (reduce + (map count-words lines))

21:23 Lewisham: ah, I thought about that, but what I actually return is a map of the words and their occurance, such as {"Me" 1, "You" 2}

21:23 that's why I was using merge-with

21:24 so it keeps merging the maps until you get one final big one

21:24 but it (understandably) barfs on a file of any large size

21:24 with a StackOverflowError

21:24 hiredman: use reduce

21:25 Mec: so count-words returns a map?

21:25 Lewisham: Mec: yes :)

21:26 (reduce (merge-with +) (map count-words lines)) ?

21:26 hiredman: you need to use partial

21:26 Lewisham: that NPEs in my code, but that's not to say it's because my count-words function is bad

21:26 hiredman: ,(merge-with +)

21:26 clojurebot: nil

21:26 hiredman: ^

21:27 ,(reduce nil '(1 2))

21:27 clojurebot: java.lang.NullPointerException

21:27 hiredman: ^-

21:27 Lewisham: ah

22:04 technomancy: just in case anyone's not following the mailing list, there's a Seattle Clojure meeting next thursday: http://bit.ly/d1rwpe

22:07 Lewisham: hiredman: Mec: somnium: I got it working, thank you :) Just have to hope I get my RAM back at some point :)

23:16 ag90: Hey I have a question. I'm working on this code and for the past few hours I was stuck on this small function. After many random printlns I concluded that it got stuck when it called a particular function. No errors. It just didn't work. When I tried that function in REPL, I got a simple error about trying to use a reference as a sequence. Worked perfectly after dereferencing. How can I enable such error messages outside the REPL?

23:16 TL;DR - I want to know if there's a way for Clojure to raise errors outside the REPL when running as a script?

23:16 technomancy: ag90: the main difference between the repl and stuff inside a script is that the repl prints everything, which forces lazy sequences to be evaluated

23:17 you can wrap a lazy sequence in "dorun" or "doall" to force it in any context

23:17 ag90: Oh. So this problem was because of laziness?

23:17 (the missing error messages)

23:17 technomancy: 90% sure it is

23:18 that's by far the most common cause of "works one way in the repl; another way in a script" problems

23:18 ag90: Oh. Great! Thanks.

23:19 technomancy: use dorun if you need return values; use doall if you just want to force the seq

23:19 or possibly replace for/map with doseq; depends on the context

23:27 tomoj: lancepantz: did you figure out the body thing with compojure?

23:27 I just needed to do that as well

23:27 I found a function in compojure called slurp-body which slurps the body into a string, but it's private

23:27 so just ended up wrapping PushbackReader and InputStreamReader to hand to c.c.json.reda

23:27 s/reda/read/

23:28 did it in middleware so in a handler (:json request) is the parsed json body

23:28 hiredman: that is a nifty idea

23:30 tomoj: it gave me an "I love clojure" moment

23:30 :)

23:32 piccolino: How would one check if a particular object is an instance of an array of bytes? I'm having trouble with isa? and instance?, neither seems to work with bytes as a parameter.

23:32 tomoj: hmm.. I feel like I also could use a macro over let which lets you bind names to values in maps in the request map, to replace (let [foo (-> request :bar :foo) bizz (-> request :baz :bizz)] ..)

23:34 ,(instance? (Class/forName "[B") (byte-array 10)))

23:34 clojurebot: true

23:34 tomoj: wonder if there is a prettier way to get (Class/forName "[B") ...

23:34 piccolino: Ah, OK, thanks.

23:34 hiredman: tomoj: not really

23:35 for type hinting there is ^bytes

23:35 #^bytes

Logging service provided by n01se.net