#clojure log - Feb 04 2010

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

0:13 itistoday: ok, still working on converting that function, at least i have a couple lines of clojure code now that the api's back up

0:13 how to fix this: http://paste.pocoo.org/show/173729/

0:14 err, rather, this: http://paste.pocoo.org/show/173730/

0:19 somnium: itistoday: that style of closing parens is rather frowned upon

0:20 itistoday: i'm sorry, but to me it makes the code readable

0:21 call it a habit from years of C-type languages

0:21 it lets me know where one block ends and another begins

0:21 err.. expression

0:22 somnium: itistoday: well, its likely to draw repeated comments

0:23 itistoday: somnium: i hold my tongue when i see people piling on their parenthesis at the end even though I feel just as you feel about my coding style

0:24 somnium: itistoday: thats what the indentation is for :)

0:25 itistoday: somnium: ok, if it will help you help me: http://paste.pocoo.org/show/173732/

0:25 somnium: itistoday: anyway, I would recommend reading about syntax-quote and experimenting with macroexpand-1

0:25 tomoj: I guess I don't need to say "just use a decent editor for lisp" eh

0:26 well, certainly not since the issue to which that's a response didn't actually come up-readability is different than editability

0:27 somnium: itistoday: http://mumble.net/~campbell/scheme/style.txt :)

0:27 tomoj: I guess the standard response about readability is "you'll get used to it"? :(

0:28 somnium: "Rationale: The parentheses grow lonely if their closing brackets are all kept separated and segregated."

0:28 hiredman: the rationale is the people in the irc channels you ask for help on like it that way

0:29 :P

0:29 tomoj: for me it would take more tabbing to reindent the lonely parens if I change something

0:29 itistoday: *sigh*...

0:29 ok... poor lonely parenthesis, excellent rational

0:29 i'll tell that to my poor lonely braces

0:30 but i already broke in, gave in to conformity and your unreadable style: http://paste.pocoo.org/show/173732/

0:31 and it still won't run :-p

0:32 hiredman: itistoday: why?

0:32 itistoday: java.lang.Exception: Can't let qualified name: user/col-syms (NO_SOURCE_FILE:32)

0:33 hiredman: itistoday: no, why are you doing this?

0:33 itistoday: oh, i'm trying to see if it's possible to write this neat newlisp function in clojure

0:33 hiredman: that is a macro, not a function

0:33 and I would hardly call it neat

0:33 itistoday: *this neat newlisp macro

0:34 that's not it

0:34 i'm building up to the newlisp one

0:34 hiredman: why?

0:34 itistoday: like i said

0:34 the newlisp macro is awesome

0:34 DeusExPikachu: I was connected to swank with emacs via slime-connect and then I got disconnected because the internet died. Unlike when I have a graceful disconnect via slime-disconnect, I can not reconnect. Is this a bug in swank? is there anything I can do to reestablish a connection to the remote swank server?

0:34 hiredman: itistoday: I doubt that

0:34 itistoday: (for-query-with-db db "SELECT name FROM people" (println NAME))

0:34 see

0:34 that's awesome

0:35 hiredman: how?

0:35 itistoday: hiredman: how is mona lisa awesome?

0:35 somnium: itistoday: it vaguely reminds me of php :P

0:35 itistoday: php can't do that

0:35 and i'm wondering whether clojure can

0:35 i assume it can

0:35 somnium: its good at mixing templating code with db access though

0:36 itistoday: yes, that's what i want it for

0:36 somnium: itistoday: it definitely can

0:36 hiredman: that is hardly different from what you would get from using contribs sql stuff

0:36 itistoday: hiredman: that's great

0:36 somnium: how?

0:36 hiredman: except with the sql stuff you get a result seq, and you don't shadow names

0:37 itistoday: hiredman: it's not shadowing names either

0:37 hiredman: it is

0:37 itistoday: no, really, it's not

0:37 hiredman: well, shadowing is not the right word

0:37 itistoday: it's only shadowing NAME in the body

0:37 "shadowing" indeed

0:37 hiredman: randomly introducing

0:37 itistoday: and NAME isn't bound to anything

0:37 yes

0:37 actually no,and it's not random

0:37 *it's not random

0:38 it's really cool

0:38 very succinct

0:38 hiredman: clojureql does that, and was recently called out in a blogpost somewhere for doing so

0:38 itistoday: clean is the word

0:38 hiredman: it's not cool

0:38 itistoday: hiredman: you're not cool

0:38 hiredman: queries as strings are not cool

0:39 itistoday: look, you don't find it cool, i do

0:39 it's a matter of personal preference

0:39 hiredman: itistoday: I'm not cool, I'm tired of your bellyaching about newlisp and passive agressive attempts to goad people into helping you by compare clojure and newlisp

0:39 hoeck: itistoday: don't worry too much about hiredman, what you want is possible in clojure

0:40 itistoday: hoeck: thanks, and i don't doubt that, but my clojure skillz are nonexistent at this point

0:40 hoeck: itistoday: in clojure.contrib.macro-utils, there is a symbol-macrolet macro

0:41 somnium: it can be done without symbol macros

0:41 itistoday: it's really hard for me to follow the docs though as they don't give examples

0:41 hoeck: though your macro is more common-lisp style, clojure has a more functional aproach, map access is cheap, just (print (:name result))

0:42 somnium: of course, but it looks like the most direct translation from his code would be to use symbol-macrolet

0:42 but correct me if I'm wrong

0:42 somnium: ,(let [form '(print a)] (for [x (range 3)] `(let [~'a ~x] ~form)))

0:43 no bot?

0:45 DeusExPikachu: found it, ":dont-close true" is the solution

0:45 at least, for the future

0:46 somnium: itistoday: whether or not the macro itself is desirable, its fairly easy with symbol capture, so again I recommend learning how syntax quote works and experimenting with macroexpand

0:46 hiredman: or just using the sql library in contrib, or use clojureql

0:47 itistoday: hiredman: i will use clojureql when i need to do serious db stuff

0:47 hiredman: right now i'm trying to learn clojure

0:47 hiredman: i think clojureql is a very neat tool btw

0:48 somnium: can you give me an example to help me get started?

0:48 i learn by example, and the docs have none :-(

0:48 somnium: clojurebot: ping

0:48 clojurebot: PONG!

0:49 DeusExPikachu: examples in the docs can go a long way, I say

0:49 somnium: ,(let [form '(print a)] (for [x (range 3)] `(let [~'a ~x] ~form)))

0:49 clojurebot: ((clojure.core/let [a 0] (print a)) (clojure.core/let [a 1] (print a)) (clojure.core/let [a 2] (print a)))

0:49 hoeck: itistoday: something like your macro already exists in clojure.contrib.sql

0:50 herdrick: tomoj: thanks for the blog post. i didn't realize you were getting error messages and ignoring them. (i might have been ok already)

0:50 DeusExPikachu: but the best examples lie in library code most of the time

0:50 hoeck: itistoday: (with-query-results ["select * from table"] result (println (:name result)))

0:51 tomoj: I think installing slime before or marking it for installation along with the rest might have solved that error, dunno

0:51 itistoday: hoeck: i'm looking at the source, and it uses a with-query-results* function, don't know where that's defined

0:52 tomoj: itistoday: what editor do you use?

0:52 hoeck: itistoday: in sql/internals.clj

0:52 itistoday: tomoj: right now just using textmate + clj

0:52 tomoj: ah, nevermind then

0:53 hoeck: tomoj: but slime-find-definition works only if the clj-file is on the classpath :(

0:54 tomoj: good point

0:54 itistoday: hoeck: this is a bit beyond me atm i'm afraid...

0:55 herdrick: tomoj: yeah - so i have some network issues right now and the install is hanging on "Downloading clojure-contrib-1.1.0-master-2009foobarbazz.jar"

0:55 itistoday: is this really that difficult of a macro to write..?

0:55 tomoj: herdrick: you can skip the install if you're going to use lein

0:55 herdrick: tomoj: can you tell me where it's installing things to so I can go wipe them all out and start over?

0:55 tomoj: well.. lein will require a working network anyway :1

0:55 herdrick: i haven't been able to find the clojure.jar it downloaded

0:55 tomoj: ~/.swank-clojure I believe

0:55 clojurebot: That is the one thing Clojure can not do.

0:56 herdrick: ah, ok

0:56 my network is sometimes ok...

0:56 tomoj: best to just delete that directory

0:56 hoeck: itistoday: never mind, thats a lot of java/jdbc stuff in there, you only understand those java APIs if you have the javadoc at hand

0:56 tomoj: I think it checks whether the directory exists to decide if clojure is installed

0:57 somnium: off-topic, but anyone looked at node.js? javascript is starting to look like an increasingly attractive host for clojure

0:57 itistoday: somnium: i have, a bit

0:57 tomoj: does that lead to clojure in the browser?

0:58 itistoday: somnium: i'm not sure how you'd run clojure through it though

0:58 somnium: tomoj: thats already possible

0:58 hoeck: itistoday: basically, it executes an sql query and returns a sequence of hashmaps

0:58 somnium: subsets of it anyway

0:58 tomoj: ah yeah, clojurescript?

1:01 somnium: its also possible to translate the core special forms directly to javascript (sort of clojure the language but not the library)

1:01 herdrick: tomoj: i killed it

1:01 somnium: this node.js is made for writing high performant servers and unix scripting in js

1:02 itistoday: ok, so i've modified it a bit: http://paste.pocoo.org/show/173735/

1:02 now i'm stuck at this: java.lang.IllegalArgumentException: let requires a vector for its binding (NO_SOURCE_FILE:77)

1:03 i think it's the interleave bit, but not sure what to do

1:03 tomoj: yeah, you didn't give a vector as the first argument

1:03 (let [foo bar] ..) not (let (baz biz) ..)

1:03 itistoday: how do i convert a list to a vector?

1:04 because i want to use interleave there

1:04 tomoj: vec takes a coll and makes it a vector

1:04 but that would need to be unquoted

1:05 hoeck: itistoday: try calling (macroexpand-1 '(foo (println NAME)))

1:05 tomoj: what is the ~'col-syms and ~'val for?

1:06 itistoday: tomoj: i was getting exceptions from them not being like that

1:06 tomoj: ah :)

1:06 fiddling is bad

1:06 somnium: itistoday: the whole expression shouldnt be syntax quoted, you need to use ` to control the evaluation

1:07 itistoday: somnium: ok, that's one thing i don't have a good grasp on, is where to put the syntax quote

1:08 tomoj: are you trying to learn about macros?

1:09 itistoday: i'm trying to rewrite a newlisp fexpr in clojure, and yes, i guess learn about macros

1:09 (along the way)

1:09 tomoj: ah..

1:09 I guess people have already said that this is not the clojure way

1:09 itistoday: tomoj: the newlisp fexpr looks like this: (for-query-with-db "SELECT name FROM people" (println NAME)) => prints all the names of the people in the db

1:10 and i'm trying to work my way to a clojure version of that

1:11 somnium: itistoday: it would be easier to write a tiny macro that captures symbols first

1:11 tomoj: oh, hmm

1:11 I figured http://paste.pocoo.org/show/173737/ is what you were trying to do

1:11 but if this is just a stepping stone

1:12 itistoday: tomoj: yeah, it is, i could convert this to use hashmaps when i know how to do that :-p

1:13 this is where i am so far: http://paste.pocoo.org/show/173738/

1:13 DeusExPikachu: in the readme, leiningen is called a build tool, it seems more like a package manager...

1:13 itistoday: i'm still getting: java.lang.IllegalArgumentException: let requires a vector for its binding (NO_SOURCE_FILE:96)

1:14 somnium: itistoday: are you using macroexpand?

1:14 itistoday: somnium: here's what i get for: (macroexpand-1 '(foo (prn NAME)))

1:14 ((let (vec (interleave user/col-syms val)) (prn NAME)) (let (vec (interleave user/col-syms val)) (prn NAME)))

1:14 hoeck: itistoday: http://paste.pocoo.org/show/173739/ is a more clojure-like version of your macro, but probably not what you want

1:15 somnium: itistoday: the usual process is: 1. rule out non-macro solutions, 2. write what the emitted datastructure should look like, 3. write a macro to emit it

1:16 tomoj: well, it prints successfully if you fix one small problem

1:16 but then you're calling nil as a function

1:16 hmm

1:17 I wonder why ((let [] nil)) gives a different error than (nil)

1:18 herdrick: tomoj: looks like it's working in Aquamacs for me. Thanks! I want to put some apache-commons jars in the classpath. should I just put them in ~/.clojure as it seems to say in the swank-clojure-default-classpath function in swank-clojure.el ?

1:18 or is there a smarter move

1:18 tomoj: well.. if you were me, I would use lein

1:18 herdrick: tomoj: i think i'm going to hold off on getting going with lein until you blog it :)

1:18 tomoj: but since you're not.. are you sure it's ~/.clojure?

1:18 hah

1:19 I don't even have a ~/.clojure

1:19 I think that's old?

1:19 herdrick: not sure, but here's most of the function in question:

1:19 (defun swank-clojure-default-classpath ()

1:19 (append

1:19 (when (file-directory-p "~/.clojure")

1:19 (directory-files "~/.clojure" t ".jar$"))

1:19 technomancy: what's the equation to model something bouncing between two poles?

1:19 like a pong ball? no gravity

1:19 herdrick: i don't know - it's the swank-clojure.el it set me up with

1:20 tomoj: herdrick: hmm, yes, you're right

1:20 herdrick: ok

1:20 tomoj: ah, it uses both

1:20 technomancy: I figure it's some combination of the frame count modulo 2x the width and the absolute value of the frame count modulo the width

1:20 tomoj: the next line down checks for ~/.swank-clojure

1:20 are your clojure/contrib jars in ~/.swank-clojure? might as well put your stuff there if so

1:20 technomancy: but I want to do it functionally rather than calculating bounces by mutating the velocity

1:20 herdrick: tomoj: you're just putting such jars in each project directory as needed?

1:21 tomoj: yes, but lein does that for me

1:21 somnium: technomancy: are you making a pong clone for emacs?

1:21 technomancy: somnium: just playing around on android

1:21 tomoj: if I wanted apache-commons for toy repls I guess I'd put the jars in ~/.swank-clojure

1:21 itistoday: hoeck: thanks, not sure how to translate that to my function though

1:22 i noticed i wasn't using the ~ on col-syms and ~vals

1:22 i've updated it: http://paste.pocoo.org/show/173740/

1:22 herdrick: tomoj: yes, clojure and clojure-contrib jars are in ~/.swank-clojure

1:22 tomoj: technomancy: you want a function for the horizontal position as a function of time?

1:22 itistoday: still still get java.lang.IllegalArgumentException: let requires a vector for its binding (NO_SOURCE_FILE:123) though

1:22 technomancy: tomoj: that's the one

1:22 itistoday: s/still still/still/g

1:23 tomoj: herdrick: if you drop other jars there they should be in the class path when you M-x slime, then

1:23 but I think you will be surprised how easy lein is to setup and use, as long as you can find the deps you need in a maven repo

1:23 herdrick: tomoj: ok - because they would only be picked up when starting with M-x slime ?

1:23 tomoj: and even when not, not too bad

1:23 yeah, you need to sayoonara and restart slime if you just added something

1:24 herdrick: otherwise,like when you start with M-x swank-clojure-project, those jars won't get picked up?

1:24 technomancy: everywhere I search they're trying to pull bloody gravity into it

1:24 tomoj: swank-clojure-project only uses what's in the lib/ dir of the project you choose

1:25 as far as I know

1:25 herdrick: ok

1:25 hoeck: itistoday: to create an expansion like (let [NAME ... ID ...] (println NAME)), you have to know the columns at compile-time, it this the case?

1:25 itistoday: no, you don't

1:25 need to do this at runtime

1:25 herdrick: thanks, tomoj it looks like I'm back with a working clojure in emacs again :) many thanks

1:25 tomoj: hmm.. the funciton looks like this /\/\/\/\/\/\, no?

1:26 itistoday: hoeck: this isn't possible?

1:26 technomancy: eh; screw it; doing it statefully is good enough for tonight

1:27 hiredman: like a sine wave?

1:27 technomancy: hiredman: like a sine wave without the curvy bits

1:27 itistoday: what's wrong with this:

1:27 user=> (macroexpand-1 '(foo (prn NAME)))

1:27 ((let (vec (interleave (NAME AGE) ["Sally" 5])) (prn NAME)) (let (vec (interleave (NAME AGE) ["Sue" 6])) (prn NAME)))

1:28 technomancy: but I think I'll just do it quick and dirty by keeping a velocity and negating it when I hit the wall

1:28 tomoj: itistoday: prn returns nil

1:28 among other things

1:28 so your first let returns nil

1:28 hiredman: http://en.wikipedia.org/wiki/File:ComplexSinInATimeAxe.gif <-- that is a sweet gif

1:28 tomoj: and then you're trying to call nil as a function, passing nil as an arg

1:28 hoeck: itistoday: of course it is, but implementing it in a clean way is slightly more advanced

1:29 tomoj: I meant that other things are wrong, not that prn returns other things

1:29 itistoday: but why does running it generate: java.lang.IllegalArgumentException: let requires a vector for its binding (NO_SOURCE_FILE:123)

1:29 tomoj: technomancy: look at abs(abs(x)%4-2)

1:30 itistoday: err... and .. i need to be able to use any functions in the body, regardless of whether they return nil

1:30 tomoj: sorry, meant to reply that to you

1:30 tomoj: that's like this \/\/\/\... where the max y value is 2 and the width of / is 2

1:30 technomancy: tomoj: awesomar

1:31 thanks

1:31 tomoj: then you can add coefficients to the x to scale time

1:32 and scale the 4 and the 2 together to change the max y value

1:32 itistoday: final question before i sign off (gotta go now): is this a hard problem or just an easy one no one wants to help me with?

1:32 somnium: itistoday: its not hard and multiple people have tried to help you

1:32 tomoj: itistoday: the body has nothing to do with it

1:32 oh, yes it does, a bit

1:33 the point is you shouldn't be calling the return value of the body as a function

1:33 itistoday: tomoj: how do i avoid doing that?

1:33 tomoj: also you need to not quote vec

1:33 that is, ~(vec instead of just (vec

1:34 itistoday: tomoj: ah, thanks! http://paste.pocoo.org/show/173741/

1:34 that prints "sally" "sue" and then throws a nullpointerexception

1:34 much better! :-D

1:34 herdrick: tomoj: btw, if you were to want the current build from git (of clojure & friends) would you git pull and mvn package in some other dir, and then copy the jars to ~/.swank-clojure ?

1:35 itistoday: tomoj: now, if i may ask, why does it throw a java.lang.NullPointerException? i assume it's cause i'm "calling the return value of the body", but i didn't know i was doing that

1:35 i'm a clojure *NEWB*

1:35 tomoj: yes

1:36 I don't know how to fix it though, sorry

1:36 look at the macroexpansion you pasted above

1:36 it has the form ((let ...) (let ...))

1:36 this means the result of the first let is being called as a function with the result of the second let as an argument

1:36 which is happening because the macro is simply returning a seq of let forms

1:36 itistoday: tomoj: ah, ok

1:38 tomoj: hmm, I figured out a way to get it to work

1:39 hoeck: itistoday: transformed my version again http://paste.pocoo.org/show/173742/

1:39 tomoj: but I don't like it at all

1:39 somnium: itistoday: http://paste.pocoo.org/show/173743/

1:39 tomoj: somnium's is a much better way than mine

1:39 hoeck: itistoday: the point is that you have to declare the NAMES used in the body

1:40 itistoday: tomoj: somnium's works without that :-D

1:40 somnium: thanks!!

1:41 somnium: now i just need to decipher wtf you did there :-p

1:41 like the -> function... read the docs on that and was confused, it's nice to have an example finally

1:42 tomoj: I have often wished for a collaboratively-edited database of simple examples

1:43 TheBusby: I'd almost be willing to volunteer to add examples to the doc strings

1:43 maybe a :example string?

1:43 itistoday: i would be completely willing to volunteer as well :-)

1:44 tomoj: hmm, I hadn't thought of embedding them in the source

1:44 I was thinking of a web app

1:44 itistoday: as a newbie, i think i have valuable ignorance to contribute

1:44 TheBusby: there are a large number of standard/common functions where the doc is very difficult to understand but a simple example would be clear

1:44 ->> is a great example

1:44 itistoday: TheBusby: -> too, indeed

1:45 TheBusby: er, sorry I meant ->

1:45 itistoday: if one of you is series about this, i'm actually serious, i would be happy to assist

1:45 TheBusby: I certainly wont find the time for another week unfortunately

1:45 tomoj: I think I remember htat defn started working on some kind of project like this

1:45 itistoday: i don't mean to toot newlisp's horn, lest i avoke the anger of hiredman, but you guys should check out its documentation, it's excellent

1:45 TheBusby: but I've been thinking about it for a month or two already

1:46 somnium: http://getclojure.org/

1:46 tomoj: yep, that's it

1:47 somnium: hmm, still not wikified I guess

1:47 tomoj: glad he hasn't given up on it

1:47 TheBusby: that and I'd like to see the examples embedded like the doc string if possible

1:47 (example ->>) just like (doc ->>)

1:47 tomoj: yeah, I was originally thinking of web-editable data

1:47 I think he's storing the examples in the source of the cljex project?

1:47 itistoday: check out newlisp's documentation: http://www.newlisp.org/downloads/manual_frame.html

1:48 TheBusby: you see an example marked as "Usage:" in the doc string sometimes though

1:49 tomoj: I guess putting the examples in the source of the project makes it so that contributions will always be good ones

1:51 somnium: maybe he could just let people imbed gist urls

1:51 itistoday: somnium: thank you again, i've read through your code now and have understood it, i think this little example of yours has gotten me 70% of the way to being able to write clojure code now :-D

1:52 tomoj: somnium: you mean put the gist url in the source and then fetch the latest revision when rendering? or?

1:52 or go to getclojure.org and submit a gist url

1:52 somnium: tomoj: that one

1:52 itistoday: i think whatever you decide to do, the examples should be inline with the documentation without having to go to other URLs

1:53 somnium: gists can display inline

1:55 or setup a lisp editing app with a js-code-highlighter and emacs key bindings, but gists are probably easier

1:55 itistoday: if you guys setup a group to do this well, i'll donate $100

1:55 i'm sure others will too

1:55 (some amount)

1:55 somnium: itistoday: just donate to clojure

1:56 itistoday: somnium: eh.. i specifically want to support the development of nice documentation for clojure

1:56 tomoj: send it to defn then :)

1:56 itistoday: who's defn?

1:57 tomoj: the owner of cljex

1:57 the project behind getclojure.org

1:58 itistoday: does he have contact info?

1:58 tomoj: I dunno

1:59 getclojure.org says "If you don't have the time, no worries, but do consider donating to Clojure if you're able." :DF

1:59 itistoday: found it: http://devinwalters.com/

2:00 TheBusby: devin -> defn nice

2:00 itistoday: cool, well hopefully i'll get in touch with him

2:01 night all, thanks again for the help

2:01 tomoj: I almost bet he'll say "send the money to clojure instead"

2:05 replaca: hiredman: wow, I like that gif!

2:12 tomoj: is finding the appropriate maven artifactid/groupid/repo for a particular project frustrating, or am I just too much of a maven noob?

2:13 eh, guess I can just install the jars locally

2:37 herdrick: tomoj: yeah, i'm not finding that either. also maven noob. and thanks much for your help earlier.

2:38 tomoj: no problem

2:39 I wonder if there is something out there I could read that would make this maven stuff make sense

2:39 I find myself browsing through apache autoindexes trying to find stuff

2:39 and no nightly builds to be seen

2:40 herdrick: tomoj: btw, if you were to want to do a build from git of clojure & friends would you 'git pull' and 'mvn package' in some other dir, and then copy the jars to ~/.swank-clojure ?

2:41 hope i'm not being too obnoxious with questions

2:41 tomoj: nah

2:41 that sounds like what I would do

2:41 herdrick: ok

2:41 tomoj: except I wouldn't do that because I just use lein

2:42 herdrick: you wouldn't build from source?

2:42 tomoj: I haven't in quite a long time

2:42 maybe if I were hacking on clojure I would, I guess

2:42 herdrick: sure

2:42 ok, thanks

2:44 tomoj: huh, master hasn't been touched in over a month?

2:44 oh, that's the author date

2:44 anyway, http://build.clojure.org/ has nightlies it seems

2:44 and lein can grab from there

2:45 so little reason to build from source as far as I can tell

2:45 herdrick: i see

2:45 tomoj: I'll probably write that lein post tomorrow

2:46 followed by a paredit post

2:46 herdrick: great, looking forward to it. i'm subscribed to your rss feed

2:46 tomoj: hah

2:46 I didn't even know I had an rss feed

2:47 that wordpress has been sitting there for months with a post titled "foo" and some random clojure code embedded in a gist

2:48 guess I'm off to a good start in the blogosphere ;)

2:53 herdrick: ha - yeah!

8:12 AWizzArd: Hi chouser

8:13 chouser: hi

8:13 hmph. lost my connection. 4.5 hours of logs gone. :-/

8:15 Chousuke: doesn't look like you missed anything interesting :P

8:15 AWizzArd: chouser: I think you are an expert for agents, so here a question: is there a good reason why await does not return from waiting for an agent to finish, when this agent throws an Exception?

8:15 chouser: heh. ok, good I guess.

8:15 Chousuke: mostly just quits and joins.

8:16 chouser: AWizzArd: hm... that may not be intentional.

8:16 AWizzArd: ,(let [x (agent 0), foo (fn [_] 55)] (println @x) (await (send x foo)) (println @x)) ; works well

8:16 clojurebot: 0 55

8:16 AWizzArd: ,(let [x (agent 0), foo (fn [_] (Thread/sleep 2000) 55)] (println @x) (await (send x foo)) (println @x)) ; also works fine

8:16 clojurebot: 0 55

8:17 AWizzArd: ,(let [x (agent 0), foo (fn [_] (Thread/sleep 2000) (throw (Exception. "bar foos")) 55)] (println @x) (await (send x foo)) (println @x)) ; also works fine

8:17 clojurebot: java.lang.Exception: Agent has errors

8:17 AWizzArd: okay, this one returns, but what happens in your clojure?

8:17 Can anyone please try to confirm that await won't return for my last example?

8:17 (where I accidently didn't remove the comment from the end of the line)

8:18 chouser: yeah, it hangs here

8:19 AWizzArd: I would think that await should return

8:19 chouser: ok, in this case it's intentional

8:19 AWizzArd: chouser: can you please explain why?

8:20 chouser: that agent is using the :fail error mode, so it's waiting for you to restart the agent so that it can finish processing its queue (and release the await)

8:21 AWizzArd: error modes.. hmm, I will investigate, thx

8:21 chouser: you may prefer to specify an error-handler

8:22 (agent 0 :error-handler (partial println "Error:"))

8:22 the-kenny: ,*clojure-version*

8:22 clojurebot: {:interim true, :major 1, :minor 1, :incremental 0, :qualifier "master"}

8:23 _fogus_: ,,

8:23 clojurebot: EOF while reading

8:23 _fogus_: I always wondered what that would do

8:24 Chousuke: commas are whitespace

8:24 ,,(+) also it only reads the first form

8:24 clojurebot: 0

8:24 _fogus_: Understood

8:29 zaphyr: hmm. does clojure bot know not to hang? :)

8:29 chouser: yes he does. He's pretty clever.

8:29 zaphyr: :D

8:29 chouser: @(promise)

8:29 ,@(promise)

8:29 AWizzArd: chouser: yes, the error-handler works. But it seems neither the agent nor the handler are able to forward the Exception to the thread which awaits the agent.

8:29 zaphyr: ,(* 3 4)

8:29 clojurebot: Execution Timed Out

8:29 12

8:29 zaphyr: ahh

8:29 :)

8:30 chouser: he doesn't actually try to solve the halting problem. He's not *that* clever.

8:30 zaphyr: yeah, but we've got clojure now, i'll try and submit a patch for that by 2011 :)

8:30 AWizzArd: Is there a mechanism for that? Currently I do a repeatedly on await-for and check agent-errors, embedded in a take-while, but that definitly is very hackish.

8:31 chouser: AWizzArd: the await just puts an action on the agents queue that will signal the await to continue. then it just sits waiting for that signal.

8:32 if you want to do something specific when the agent errors out, just put that in your error-handler

8:34 AWizzArd: I would like the error handler to throw an exception in the thread which called await :)

8:44 chouser: hmm

8:44 are you sure you want agents? that all sounds very synchronous. :-)

8:46 AWizzArd: chouser: I want to modify my DB (insert/update/delete) and log to disk. I discussed this in the last days, and there are two possible solutions:

8:47 1. I use refs. But the ref would have to write to disk inside the dosync, because this is part of the transaction. This means that if many threads try to update the db the dosyncs will block each other, because the writing to disk makes them slow enough to get repeated.

8:47 This means that the dosync has to get embedded into a locking. hiredman pointed out that currently there are no plugins for dosyncs that would allow me to go around the lock

8:48 2. Chousuke then asked why I need refs if they are inside a locking anyway. So, agents also sound nice.

8:48 chouser: what about an atom and a watcher?

8:48 er, a "watch"

8:49 or a watch on a ref, for that matter.

8:49 AWizzArd: yes, atoms could be another way, maybe with a BlockingQueue or a watcher.

8:49 chouser: a watch on a ref will not prevent other transactions from working on the ref, nor cause the current transaction to retry

8:51 AWizzArd: Well, only one transaction can work at a given time on the db. One ref modifies it, so all other transactions that are running would notice the change and retry. I think.

8:52 chouser: yes, but the transaction is "done" by the time the watch is called. Other transactions can proceed with updating the db while the watch writes it to disk.

8:53 AWizzArd: chouser: this is not acceptable. Before any part of the program can see the updated db it must already be written to disk.

8:54 otherwise the change maybe happened in ram, a customer bought something, and then the system crashes before the data is on disk.

8:54 Only after the guaranteed write happened the rest of the world may know about the new state.

8:55 So, modifications to the db really need to run serial

8:55 chouser: so you really do want synchronous behavior

8:55 AWizzArd: yes

8:56 lock around dosync, agent or atom+BlockingQueue

8:56 agents sound great, they only have the problem that I reported above, with the Exceptions

8:56 chouser: I think a simple lock might be best

8:57 AWizzArd: hmm yes right, a lock around a dosync or function that updates an atom

8:57 chouser: well, agents are for async operation. I think they could be made to work in your situation, but it'll take some effort because it's not really the right mechanism.

8:57 AWizzArd: the blockingqueue would not be needed when a lock is involved

8:57 chouser: no, not a transaction. just a lock

8:58 AWizzArd: inside this lock I need to change the state of the db in clojure terms. So inside this lock I will need to update a ref, atom or agent

8:59 chouser: hm

9:00 AWizzArd: but it could be okay to have one function which is doing all the updates/inserts/deletes etc, and the db is an atom, and around my function i have a lock

9:00 chouser: an atom is close, but because you have side-effects, you don't want to retry ever.

9:00 so maybe this is essentially a new reference type.

9:00 like atom but using a lock instead of CAS

9:00 and no rhickey here to talk me down.

9:00 AWizzArd: :-)

9:01 As soon this db-transaction-function is working, all other threads can still run selects on the db

9:01 this can be done with atom updates inside a lock

9:01 chouser: you want all threads to see the old value until the new value is written to disk, right?

9:01 AWizzArd: exactly

9:01 chouser: and anything updating the value should block until its done.

9:02 and we can use protocols...

9:03 AWizzArd: until yesterday i thought i would go with a lock around a dosync. The updates can work likes this: the transaction begins and the ref is dereferenced. This immutable dereferenced db object gets "modified". If this does not trigger any constraint we now have an immutable db object which contains the correct updates.

9:03 If the program crashes here it's no problem, nobody was ever reported the updates.

9:03 If it does not crash we write to disk and wait until it is guaranteed on disk.

9:04 When the program crashes here after a restart it will have the full db contents, as if it didn't crashed, because it could read it from disk.

9:04 If we don't crash, *then* a ref-set really updates the object, the transaction ends.

9:05 or well, ref-sets are not needed

9:05 probably alter is used, nobody can see the altered db object anyway

9:05 and this allows transactions inside other transactions

9:05 jcromartie: wow, cool stuff on profiling with jvisualvm http://www.fatvat.co.uk/2009/05/jvisualvm-and-clojure.html

9:05 AWizzArd: only when the outermost dosync ended the world can see this update

9:05 jcromartie: I didn't even realize it came with Java

9:06 I hope that sort of thing doesn't go away now that Sun is no more

9:07 AWizzArd: chouser: indeed, a modification of a ref/dosync maybe meaningful

9:07 chouser: AWizzArd: I think a lock and an atom would be better.

9:08 AWizzArd: chouser: yes, also okay, though this would imly that i first deref the atom and put the derefd db into a new atom, which i then modify through the whole transaction

9:08 imly => imply

9:08 chouser: oh, you don't just have a simple update fn you call per db update?

9:09 you have a series of imperative ref-set's (or similar)?

9:09 AWizzArd: yes, this is used, but all wrapped into a db-transaction

9:10 ,(let [x (ref {})] (dosync (println @x) (alter x assoc :a 1) (println @x) (alter x dissoc :a) (println @x)))

9:10 clojurebot: {} {:a 1} {}

9:10 chouser: :-/ not very functional is it.

9:10 AWizzArd: true, but we are talking about a db transaction

9:10 this is all about state change, and not a functional thing

9:11 as if we call alter/commute inside a dosync

9:11 this non-functional style is the essence of db modifications

9:11 inside a transaction the user can do several calls to insert/update/delete

9:12 after an insert he will expect to be able to select the inserted object

9:12 chouser: right, and you can do the same inside a reference type updater (atom, ref, agent, etc.) but the Clojure API discourages it.

9:13 you're sure you want to encourage it?

9:13 jcromartie: profiling lesson of the day: MySQL connections are cheap, reading results is expensive

9:13 AWizzArd: chouser: I don't see a plausible way around this.

9:14 I hope the users will write a mostly functional style program, and isolate their db updates to a few parts of the program

9:14 chouser: anyway, if you really want to do this, I think a lock per transaction best provides the semantics you want.

9:14 AWizzArd: yes

9:15 so, lock around a function which then either modifies a ref inside dosync, or which uses an atom, derefs it, atoms it again, uses this copy inside the transaction, and when everything is done (reset!)’s the original db that can be seen by all threads.

9:16 For now I think I will be safe with lock+dosync, although this has a slightly bitter taste. But if it turns out that there is a better solution I can still update to that solution.

9:17 chouser: interesting discussion, thank you. Brought new information for me.

9:19 chouser: once you're inside a lock, a ref and transaction is much heavier than you need. I would look at using an atom or maybe even something lighter than that.

9:20 AWizzArd: chouser: there is nothing lighter than an atom

9:20 chouser: perhaps (with-db-transaction [x my-db] ... (db-set x foo) ... (db-alter x bar) ...)

9:21 then with-db-transaction can create a new mutable instance and bind it to x. should be safe because x won't exist outside the dynamic scope of with-db-

9:21 AWizzArd: And I am not so sure that a ref will be indeed so heavy. It will never notice any updates by other threads, because it is the only one running.

9:22 chouser: so there need be no serializing changes to x at all. it could be even just a clojure.lang.Box

9:22 hm.. actually, that sounds like a var

9:22 AWizzArd: I don't know Box

9:22 And can a var be updated?

9:23 chouser: (doc with-local-vars)

9:23 clojurebot: "([name-vals-vec & body]); varbinding=> symbol init-expr Executes the exprs in a context in which the symbols are bound to vars with per-thread bindings to the init-exprs. The symbols refer to the var objects themselves, and must be accessed with var-get and var-set"

9:23 qed: http://www.infoq.com/interviews/Steele-Interviews-John-McCarthy

9:23 AWizzArd: and why does with-db-transaction not require serializing changes to x?

9:24 chouser: because with-db- does the locking, outside which x doesn't even exist.

9:25 AWizzArd: chouser: yes, but x needs to be changed inside

9:30 ,(let [x (atom 0)] (with-local-vars [foo @x] (println foo) (println @foo)))

9:30 clojurebot: #<Var: --unnamed--> 0

9:31 chouser: ,(with-local-vars [a 10] (var-set a 5) @a)

9:31 clojurebot: 5

9:31 AWizzArd: chouser: I will analyze this w-l-v, and maybe this is giving me the right semantics.

9:32 But one problem could be that several of those can run in parallel

9:32 So, a lock around that will still be required

9:32 chouser: oh, yes.

9:32 the var shouldn't even exist except inside the locking construct

9:32 AWizzArd: Anyway, maybe it is even lighter than an atom and thus run more efficient

9:33 chouser: you mentioned this for efficiency, right?

9:33 chouser: and safety, yes.

9:34 AWizzArd: chouser: good point, this (locking+w-l-v) may provide the same as locking+atom+atom or locking+dosync, but more efficiently

9:36 the locking around the dosync would in principle not be required, but I would use it, because the io operation inside makes it slow and could trigger too many repetitions of the dosync

9:38 * esj runs screaming back to his single threaded db model

9:39 AWizzArd: esj: just give me a few more weeks please :-)

9:39 esj: AWizzArd: provided you explain it to me when you're done !

9:40 AWizzArd: I am spending a lot of time on documentation.

9:40 And.. when even I can understand it, it must be pretty simple.

9:40 * qed gives AWizzArd a huge

9:40 qed: hug*

9:41 ^--------oOOops

9:42 esj: AWizzArd: thanks i really appreciate well doc'd code, helps so much to understand

9:42 fdaoud: ,(zipmap [1 2 3 4] ["a" "b" "c" "d"])

9:42 clojurebot: {4 "d", 3 "c", 2 "b", 1 "a"}

9:43 fdaoud: ,(for [x [1 2 3 4] y ["a" "b" "c" "d"]] [x y])

9:43 clojurebot: ([1 "a"] [1 "b"] [1 "c"] [1 "d"] [2 "a"] [2 "b"] [2 "c"] [2 "d"] [3 "a"] [3 "b"] [3 "c"] [3 "d"] [4 "a"] [4 "b"] [4 "c"] [4 "d"])

9:43 fdaoud: how would you loop through 1 "a", 2 "b", 3 "c", 4 "d" *in order* ?

9:44 spariev: AWizzArd: can you shed some light on your project ?

9:45 the-kenny: fdaoud: If you have a list like [1 "a", 2 "b"] etc. you can use partition to create pairs

9:45 Chousuke: fdaoud: you can map over them

9:45 chouser: AWizzArd: maybe something like this: http://paste.lisp.org/display/94354

9:45 Chousuke: ,(map vector [1 2 3] '[a b c])

9:45 clojurebot: ([1 a] [2 b] [3 c])

9:46 chouser: heh. now there's an example where you *could* ->> and you really really shouldn't.

9:46 qed: why can't you search google for "->>"

9:47 fdaoud: ,(for [[x y] (map vector [1 2 3] ["a" "b" "c"])] [x y])

9:47 clojurebot: ([1 "a"] [2 "b"] [3 "c"])

9:47 chouser: qed: dunno, but you can (doc ->>)

9:47 fdaoud: Chousuke: thanks!

9:47 Chousuke: fdaoud: the for is redundant though :P

9:47 qed: chouser: *nod*

9:47 Chousuke: fdaoud: map is enough

9:48 fdaoud: Chousuke: agreed, but I need to put this in a for-like structure, so just making sure it behaves as expected :)

9:48 Chousuke: ,(map + [1 2 3] [4 5 6]) another example

9:48 clojurebot: (5 7 9)

9:48 tcrayford: ,(for [x [1 2 3] y '[a b c]] [x y])

9:48 clojurebot: ([1 a] [1 b] [1 c] [2 a] [2 b] [2 c] [3 a] [3 b] [3 c])

9:48 _fogus_: ,(partition 2 (interleave [1 2 3] '[a b c]))

9:48 clojurebot: ((1 a) (2 b) (3 c))

9:48 fdaoud: tcrayford: I don't want 1 a 1 b 1 c, just 1 a 2 b 3 c

9:49 Chousuke: specifically, Enlive's clone-for

9:49 tcrayford: ,(use 'clojure.contrib.seq-utils)

9:49 clojurebot: nil

9:49 tcrayford: (indexed [a b c])

9:49 ,(indexed [a b c])

9:49 clojurebot: java.lang.Exception: Unable to resolve symbol: a in this context

9:49 tcrayford: ,(indexed '[a b c])

9:49 clojurebot: ([0 a] [1 b] [2 c])

9:49 chouser: an antipattern. don't you dare: http://paste.lisp.org/display/94354#1

9:50 Chousuke: wait, what

9:50 fdaoud: Chousuke: ?

9:50 Chousuke: that paste

9:51 chouser: what, you don't like to put your 'finally's before your 'try'?

9:51 fdaoud: well, anyway, map vector is what I needed, thanks :)

9:52 ,(interleave [1 2 3] '[a b c])

9:52 clojurebot: (1 a 2 b 3 c)

9:52 fdaoud: _fogus_: thanks, another way of doing it

9:53 Chousuke: chouser: it's scary that that's even possible.

9:53 chouser: putting the 'let' last is still my favorite.

9:54 ,(->> (+ a 5) (- 20) (let [a 9]))

9:54 clojurebot: 6

9:54 Chousuke: it's unfortunate that the more expressive a given feature is, the more opportunities it offers for abusers :P

9:54 chouser: ok, it's not.

9:55 not my favorite, I mean.

9:55 Chousuke: yes, scary.

9:55 tcrayford: I wrote a thing in emacs that'll turn any ->> expression into its normal form, and vice versa

9:55 is fun to play around with on crazy code

9:56 chouser: tcrayford: ooh, neat.

9:56 I usually end up writing without ->> first, and then converting.

9:56 tcrayford: I had fun when I learned about ->>, and wrote that

9:56 then tried it on a page or two of code for kicks

9:57 then decided its only worth it sometimes

9:57 so converted most of it back to normal code

9:57 * cemerick can't wait until -?>> is folded in

9:57 tcrayford: what does -?>> do?

9:57 cemerick: same as -?>, but for ->>

9:58 * qed oohs and ahs

9:58 qed: i've never seen the -?>

9:58 :\

9:58 cemerick: it's in clojure.contrib.core

9:58 Chousuke: isn't it just (defnilsafe -?>> ->>) :/

9:58 qed: ah

9:58 cemerick: Chousuke: yes, but it should be "out there"

9:59 AWizzArd: spariev: I am working on an in-memory, in-process DB system, written in Clojure, and very easily usable in Clojure.

10:00 spariev: AWizzArd: tnx

10:02 Is it going to be relational or object DB ?

10:06 AWizzArd: spariev: object

10:07 chouser: yes, this example code is in principle modeling this transaction subsystem

10:10 jkdufair: so does ->> do its "threading" prior to evaluation? it would be a macro, yes?

10:10 tcrayford: confirm

10:10 Chousuke: yes.

10:10 tcrayford: ,(use 'clojure.contrib.repl-utils)

10:10 clojurebot: java.lang.ExceptionInInitializerError

10:10 tcrayford: ,(source ->>)

10:10 clojurebot: java.lang.Exception: Unable to resolve symbol: source in this context

10:10 tcrayford: :(

10:10 jkdufair: thx

10:10 spariev: AWizzArd: I'm asking because I'm thinking about some kind of Functional Relation Programming DB, with relations and stuff. basically I'm trying to wrap hypersonic sql with some clojure

10:10 chouser: right, which is the only reason you can do crazy stuff with let, try/finally, etc.

10:10 Chousuke: ~def ->>

10:11 AWizzArd: spariev: interesting

10:11 spariev: AWizzArd: and your discussion with chouser was very helpful )

10:11 AWizzArd: great

10:12 chouser: AWizzArd: so you like the example code -- what about the implementation. about as simple and performant as it gets, I think.

10:13 the only way to replace the outer atom properly, I think, would require a volatile field.

10:13 AWizzArd: chouser: I am currently in the process of finding my for now "final model", and the w-l-v may be the most efficient solution and thus I am analyzing this. When I can not identify major challenges it will be my route for now.

10:13 chouser: ok

10:13 AWizzArd: Good that you brought this to my attention.

10:14 From the point of correctness many solutions are okay, but obviously I want something efficient.

10:14 Given that sorted sets/maps are still amazingly slow...

10:15 chouser: I think this solution is less "against the grain" than trying to make agents synchronous

10:15 AWizzArd: Can you please join me begging rhickey to implement PersistentSortedMultisets and sets? :)

10:15 chouser: yes, makes sense

10:15 chouser: he had multi-maps (not sorted I think), but seemed to think that everyone's response was underwhelming, so dropped it.

10:16 AWizzArd: ooh ooh

10:16 maybe he still has the code somewhere

10:16 Yesterday I discovered that Google offers nice immutable collections: http://code.google.com/p/google-collections/

10:17 But after a closer look I realized that what they created within two years just can't compete with what rhickey implemented.

10:17 The google collections are immutable but not persistent

10:17 chouser: yeah

10:17 AWizzArd: I can not look from 10 different threads at them and modify them in an isolated way

10:17 I can not remove things

10:18 they are more like "constant sets"

10:18 I just saw they offer Multisets and Multimaps and even BiMaps

10:18 chouser: AWizzArd: http://clojure-log.n01se.net/date/2009-09-03.html#12:03c

10:18 cemerick: I didn't mind the multi-maps at all, it was having distinct reader syntax for them that didn't make sense for me.

10:19 rhickey: AWizzArd: it is pretty easy to write a multimap api on top of maps of sets

10:19 AWizzArd: And having those Multisets/maps would be really helpful. But having SortedMultisets would indeed be a killer feature

10:20 rhickey: AWizzArd: what's the killer use case for sorted multisets?

10:20 AWizzArd: rhickey: Adding 80k users (deftype User [username password age city]) into the sorted multiset, sorted by their year of birth

10:20 chouser: rhickey: AWizzArd thinks he wants a synchronoush reference type, but based on locks not CAS like atom so that he can do side-effects without repeating them.

10:21 AWizzArd: currently this requires a unique field. I can not simply have the comparator sorting by year of birth, because more than one user was born 1970

10:21 I will have to include a slot from the User deftype which is unique.

10:21 rhickey: chouser: like the cells? this unrelated to multisets?

10:21 chouser: rhickey: so I wrote this and wanted to give you an opportunity to declare it should never be used. :-) http://paste.lisp.org/display/94354

10:21 AWizzArd: In a SortedMultiset I could just add all users

10:22 rhickey: unrelated

10:22 chouser: urg. I forgot about cells. hang on.

10:22 AWizzArd: I want to do io (writing to disk) inside a dosync

10:22 rhickey: so this developed to become a lock around a dosync

10:22 rhickey: AWizzArd: but why multiset and not multimap? it's not a set of years

10:22 AWizzArd: rhickey: to get all people born between 1970 and 1980

10:23 this would return one set of users, if subset were implemented

10:23 rhickey: AWizzArd: but a set of people is not a set of years

10:23 chouser: AWizzArd: you didn't like this solution? http://paste.lisp.org/display/94065

10:24 AWizzArd: (sorted-multiset #(compare (:yob %1) (:yob %2))) is very nice. And later (subset users-by-yob = 1964) ==> all users born in this year. Or (subset users-by-yob >= 1970, < 1980) ==> returns a set of users that fulfill this criteria

10:24 chouser: this works but is more complex

10:25 and what can we do if the deftype has no slot that contains a unique value?

10:25 Also it makes the lookup more complex

10:25 a sorted-multimap would also work, but this would not return one set, but instead a sequence of keys (year of birth here) and values (sets of User instances)

10:26 Also it would be amazing if a subset was in reality just a "view" (shared structure) of the map, so it won't take much ram

10:26 don't know if this is possible

10:26 chouser: hm, cells might work.

10:26 qed: is a sorted-multimap more abstract than a multimap, or vice versa?

10:27 rhickey: a multiset is sort of a contradiction

10:27 chouser: heh

10:27 AWizzArd: rhickey: well, they may be equal under the comparator, but they are not identical?.

10:27 chouser: yeah, a cell would work

10:28 rhickey: AWizzArd: it's just a logical mess. What is it a set of? Does it enforce set-ness of the entire thing when using a partial key?

10:28 AWizzArd: Google also has Multisets in their Collections. Though as I already said, what you developed for Clojure is way more advanced than the immutable collections from Google.

10:29 rhickey: AWizzArd: collection class libs have had multisets for decades, still confusing

10:29 AWizzArd: It would be interesting to be able to call (subset on-it), to get a set returned on which one can call intersect.

10:29 Example: you have a sorted set of all male users and a set sorted by year of birth. You could then look up males, then all born between 1990 and 1995 and intersect those and have all male users born during that time.

10:30 rhickey: AWizzArd: sounds like indexes

10:30 AWizzArd: rhickey: exactly!

10:30 I am talking about indexes.

10:30 rhickey: not collections

10:31 AWizzArd: Well, the index needs to reside in some collection.

10:31 The index we are talking about lives in ram and is persistent.

10:31 rhickey: all you need are multimaps for indexes

10:31 AWizzArd: rhickey: yes, those are enough in principle. They can just not be so easily queried

10:32 rhickey: AWizzArd: I don't see why not

10:32 esj: AWizzArd I've been doing something similar to this, a timeseries library, where I also used a sorted-set-by for the concerete representation. Made much easier by the fact that time is the unique index. Its nothing special, but check it out - https://gist.github.com/1eaa8e674ec13a06559b

10:32 AWizzArd: If you make such a map that logs the msecs after 1970 (timestamp) of user requests in your webserver

10:32 How would we then ask for all requests between 2008 and 2009?

10:33 That would require many lookups, as many as there are msecs per year

10:33 And most will result in nil

10:33 A sorted multimap would be more useful here

10:34 such as subseq can already return such results easily for sorted sets and sorted maps

10:34 qed: esj: very cool

10:35 esj: i'm hoping to get it into Incanter once its been gone over by somebody who actually know what they are doing :)

10:35 qed: im bookmarking to read when i wake up :)

10:35 AWizzArd: And even when subseq returns a result, we still have to apply clojure.set/union on all those little values returned from the map

10:35 qed: thanks

10:35 AWizzArd: a set however makes this easier to query. A set will return the Log objects directly. The comparator would compare their incoming timestamp and sort them.

10:36 Although, so far there is no .subset implemented and it is also a seq

10:36 qed: i like sets

10:36 AWizzArd: qed: yes, I also

10:36 rhickey: AWizzArd: sorry, I meant both sorted and non-sorted multimaps above. What I am arguing against is multisets

10:36 qed: they're dependable

10:36 esj: and they like the attention

10:37 qed: haha

10:37 AWizzArd: rhickey: the SortedMultimaps are able to model everything what I can come up with. The only thing that is not so nice about them is that they return key/value pairs, instead of the union of all values.

10:38 chouser: AWizzArd: my db-locking thing doesn't protect against nesting the way it should (and cells would)

10:38 AWizzArd: If there were a function subset that I could call on a SortedMultimap that would be fine of course.

10:38 qed: AWizzArd: yeah but i think the key/val pairs makes more sense -- seems more consistent

10:38 rhickey: AWizzArd: a multimap might return a set at each key

10:38 AWizzArd: rhickey: yes. And on those we need to call (apply clojure.set/union ..)

10:39 A SortedMultiset would do this implicitly.

10:39 qed: it might be a bit much, so to speak

10:40 AWizzArd: (deftype Log [timestamp method uri user])... (def logs-by-timestamp (sorted-multiset #(compare (:timestamp %1) (:timestamp %2))). And later we can (subset logs-by-timestamp >= (to-timestamp 2008) < (to-timestamp 2009))

10:40 And the result would be a set of Logs. Even if two requests arrived at the same msec

10:41 A sorted-multimap instead would return a sequence of 4 million key/value pairs that I first need to union.

10:41 I need to union them to be able to intersect them with other selections

10:41 rhickey: AWizzArd: but you are only looking at one aspect. There is a lot of confusion engendered by multisets using partial keys. Are they true sets? How does contains? work? is there a way to check for containment of a full value? etc etc

10:41 qed: AWizzArd: i see the utility, but im not convinced by your example

10:43 AWizzArd: also an interesting point is if the union of some thousand sets, summing up to a million objects will have to be a full copy of those, or if it could "magically" be some kind of view on the existing sets under the hood.

10:43 in such a case clojure.set/union|intersect|difference would be fast and not require too much RAM.

10:44 sorted-sets are already pretty close to sorted-multisets

10:44 uhm, I mean: sorted-maps are already very close to sorted-multisets

10:45 What I am currently doing is using a sorted-map-by and when a key does not exist I assoc an empty set as its value. Otherwise I assoc the set conjed with the new value to the sorted-map

10:46 Thus I already have something very close to a Multiset. My value, the set, is indeed not even a set, but itself a sorted-set. This way I could for example store users by their year of birth, and have them alphabetically sorted.

10:47 having sorted-multisets support in Clojure would of course be very helpful

10:48 We could have them just implement the SortedMap interface (as suggested in the assembla ticket), or if we want Java 6, implementing the NavigableMap interface.

10:49 Well, thanks for listening. rhickey, it is true that I mostly look at one aspect of SortedMultisets, but even having SortedMultiMAPs would be very interesting.

10:50 chouser: I listened to you, but could not respond. What are those Cells?

10:50 angerman: handling JNA structs with clojure is not very elegant ... or I'm doing something completely wrong.

10:53 chouser: AWizzArd: rhickey described them here: http://clojure-log.n01se.net/date/2010-01-22.html#09:22a

10:55 AWizzArd: chouser: very good, I will read this

10:56 rhickey: btw, do you see a way to make something like "transient sorted-maps/sets"? I am looking for a way to insert data into sorted maps/sets much faster, and I can guarantee to insert in the correct order.

10:56 Would that be possible, in principle?

10:58 cemerick: those cells sound like very concrete monads to me

10:58 not that I pretend to properly understand monads

10:58 rhickey: cemerick: monads you can use from multiple threads? a contradiction in terms I think

10:59 monads are about flow, this is about not having to flow

10:59 AWizzArd: I'm not sure how much perf advantage to transient sorteds, probably some, just tedious

11:00 AWizzArd: hmm

11:00 rhickey: AWizzArd: i.e. with transient updating you could just do local mutative rebalancing, rather than full path copies

11:00 AWizzArd: I was thinking about this: when a savepoint of the db is made and an application restarted, it then wants to reload the db. Insertion is not very fast into sorted-maps/sets. I just know that I have them already sorted on disk, because I read them out of a sorted-map/set during serialization.

11:01 rhickey: fast load from sorted is a different question

11:02 AWizzArd: ,(time (let [x #{}] (reduce #(conj %1 %2) x (range 1000000)) nil))

11:02 chouser: could perhaps avoid a lot of rebalancing if you know the size of the input and the fact it's sorted

11:02 clojurebot: Execution Timed Out

11:02 AWizzArd: ,(time (let [x #{}] (reduce #(conj %1 %2) x (range 100000)) nil))

11:02 clojurebot: "Elapsed time: 964.84 msecs"

11:02 AWizzArd: ,(time (let [x (sorted-set-by <)] (reduce #(conj %1 %2) x (range 100000)) nil))

11:02 clojurebot: "Elapsed time: 2438.971 msecs"

11:03 cemerick: rhickey: I've never used monads at all, so this is mostly hot air. Cells seem to share the notion of cleanly separating initial states, operations, and later states that are the result(s) of those operations.

11:03 AWizzArd: chouser: yes

11:03 And I won't need the comparator, comparison is not needed

11:03 ,(time (let [x []] (reduce #(conj %1 %2) x (range 100000)) nil))

11:03 clojurebot: "Elapsed time: 134.741 msecs"

11:03 AWizzArd: fast :-)

11:04 unfortunately I can not use vectors as indexes

11:04 anyway, rhickey, now after more study about your implementations of those data structures I am very impressed what you have done. It is very good work, and you easily outperform Google! *thumbs up*

11:05 chouser: ,(time (peek (into [] (range 100000))))

11:05 clojurebot: 99999

11:05 "Elapsed time: 106.663 msecs"

11:05 chouser: faster

11:06 AWizzArd: ,(time (count (into #{} (range 100000))))

11:06 clojurebot: 100000

11:06 "Elapsed time: 225.935 msecs"

11:06 AWizzArd: ,(time (count (into (sorted-set-by >) (range 100000))))

11:06 clojurebot: 100000

11:06 "Elapsed time: 1834.843 msecs"

11:08 AWizzArd: chouser: I will see if I can easily enough go around the problem of stacked transactions using with-local-vars. Otherwise for now I can simply use a lock, deref the atom containing the db, atoming it again and reach this around.

11:08 And when Cells come one day, I could use them and clean up my underlying implementation.

11:09 chouser: it wouldn't be hard to add protection against nested with-db-locks

11:10 AWizzArd: yes, I will most likely do that

11:10 I will come up with a prototype of db-transactions this week

11:10 chouser: AWizzArd: would you ever want to support updating multiple dbs in the same transaction?

11:11 AWizzArd: chouser: probably not. My db will be a little bit like git/mercurial and allow clones ("branches") which can be merged.

11:11 During the merge there will be two dbs involved, but that should still not require refs.

11:12 anyway, for today I have talked enough, and our discussion about the efficiecy was very interesting and shed new light on some aspects for me. For example, I didn't know about with-local-vars.

11:23 stuartsierra: Anyone have a better link for Rich's talk at Clojure NYC last week?

11:25 rhickey: stuartsierra: I didn't know it was being recorded

11:25 stuartsierra: rhickey: someone had a flip

11:26 There's an incomplete video here: http://vimeo.com/9090935

11:26 rhickey: yeah, with a low battery :(

11:26 stuartsierra: yep

11:26 I wanted to share it with my interns.

11:31 rhickey: stuartsierra: you have to bring them next time!

11:32 stuartsierra: They couldn't make it. I invited them.

11:33 fdaoud: where was this?

11:34 sorry, you said NYC

11:35 of course the other one is on Scala

11:36 the syntax of which I cannot stand

11:38 stuartsierra: fdaoud: Clojure NYC, on meetup.com

11:49 qed: I so wish there was a meetup in Chicago

11:51 chouser: qed: If there were, I might go.

11:51 a bit of a treck, but could be worth it. :-)

11:54 wtetzner_: does anyone know how to set jvm options for swank-clojure?

11:54 chouser: qed: would you present something?

11:55 mattrepl: wtetzner_: it used to be swank-clojure-extra-vm-args that you could set

11:55 wtetzner_: mattrepl: ok, i'll try that. thanks

11:56 mattrepl: it takes a list of string arguments: (list "-Dsome.prop=10" "-Xmx1024m")

11:58 wtetzner_: ok, thanks

12:00 i'm trying to use jvisualvm for profiling, but it tells me i have class sharing turned on

12:00 i tried using -Xshare:off, but it still says sharing is turned on

12:01 mattrepl: once you have swank-clojure loaded up, you can also see/set all the settings from M-x customize-group

12:01 using "swank-clojure" as group name

12:02 wtetzner_: ok

12:02 jcromartie: how would I make a case-insensitive regex?

12:02 chouser: #"(?i)foobar"

12:03 jcromartie: ah

12:03 is that in the docs anywhere?

12:03 chouser: it's in the book. ;-)

12:03 jcromartie: ah

12:03 clojure.org feels sorely out of date sometimes

12:03 * technomancy wonders if he'll ever remember the syntax for that

12:03 jcromartie: it would be trivial to update it if the wiki were open

12:03 (is it?)

12:03 chouser: well, it's take directly from the Java Pattern object

12:03 jcromartie: ah

12:04 I thought the options were specified as arguments to the constructor

12:04 chouser: http://java.sun.com/javase/6/docs/api/java/util/regex/Pattern.html#UNIX_LINES and following

12:06 jcromartie: thanks

12:23 alexyk: what's the syntax for if -- elseif ... -- else, if any? nested ladders of if's start to look unwieldy... is there a caseof equivalent?

12:25 or it's a big-arse (if ... (if ... ))))))) <-- the famous painfully counted closing layered cake?

12:25 the-kenny: alexyk: case? cond?

12:25 alexyk: the-kenny: ah!

12:26 _fogus_: alexyk: (and)

12:26 alexyk: _fogus_: (and)?

12:26 ,(doc cond)

12:26 clojurebot: "([& clauses]); Takes a set of test/expr pairs. It evaluates each test one at a time. If a test returns logical true, cond evaluates and returns the value of the corresponding expr and doesn't evaluate any of the other tests or exprs. (cond) returns nil."

12:26 fdaoud: , (cond (< 2 42) "a" (> 2 42) "b"))

12:26 clojurebot: "a"

12:27 alexyk: ,(doc case)

12:27 clojurebot: "clojure.contrib.fcase/case;[[test-value & clauses]]; Like cond, but test-value is compared against the value of each test expression with =. If they are equal, executes the \"body\" expression. Optional last expression is executed if none of the test expressions match."

12:27 alexyk: aha, so case is not core

12:27 Chousuke: will be in 1.2

12:28 stuartsierra: and it's different

12:28 alexyk: stuartsierra: different from the above fcase/case?

12:29 _fogus_: I used (and ...) to essentially simulate elsif, it's unwieldy too

12:29 stuartsierra: alexyk: yes

12:29 _fogus_: alexyk: Yeah, it's a total hack

12:31 somnium: how is that fcase macro different from condp?

12:31 stuartsierra: it's not

12:31 I wrote it before condp existed

12:31 somnium: ah, roger

12:31 alexyk: ,(doc condp)

12:31 clojurebot: "([pred expr & clauses]); Takes a binary predicate, an expression, and a set of clauses. Each clause can take the form of either: test-expr result-expr test-expr :>> result-fn Note :>> is an ordinary keyword. For each clause, (pred test-expr expr) is evaluated. If it returns logical true, the clause is a match. If a binary clause matches, the result-expr is returned, if a ternary clause matches, its result-fn, which must b

12:32 alexyk: I'll stick with cond, clear and unambifuous. Not much trouble to write (= var blah)

12:32 stuartsierra: yej

12:32 yes

12:33 And for simple tests, it's faster than case

12:34 alexyk: yeah, I'm branching on a keyword values

12:34 i.e., on a var values which are keywords

12:48 jcromartie: speaking of condp, is there anything that acts like the typical curly-brace "switch"?

12:52 deafmacro: hello, is there a way to cancel a task sent to an agent?

12:54 jcromartie: deafmacro: nice nick :)

12:54 deafmacro: could you send a fn that depends on a ref that you can toggle from somewhere else?

12:54 deafmacro: jcromartie: heh thanks :)

12:56 jcromartie: ,(let [cancel-ref (ref nil)] (fn [] (when-not @cancel-ref (println "Doing my thang"))))

12:56 clojurebot: #<sandbox$eval__4729$fn__4731 sandbox$eval__4729$fn__4731@176dad5>

12:56 deafmacro: I could but would it stop the agent?

12:56 jcromartie: it wouldn't *stop* the agent, but you have control over what fn you send to it

12:58 ,(let [cancel-ref (ref nil) job (fn [] (when-not @cancel-ref (println "Doing my thang")))] (job))

12:58 clojurebot: Doing my thang

12:58 jcromartie: ,(let [cancel-ref (ref nil) job (fn [] (when-not @cancel-ref (println "Doing my thang")))] (dosync (ref-set cancel-ref true)) (job))

12:58 clojurebot: nil

12:59 jcromartie: just an idea

13:01 deafmacro: jcromartie: thanks! will take that approach and see what I get

13:01 jcromartie: that's probably a cleaner way than killing a thread :)

13:02 deafmacro: jcromartie: true. the java docs recommed the same. makes sense too. one would want to control how the thread exits

13:03 jcromartie: yeah at least in the iPhone/ObjC world that I work in most of the time some very nasty things can happen when something goes wrong in a thread... but that's mostly because it's not GC'ed

13:04 somnium: somehow that mechanism makes me think of bureaucracy (upon receiving an order, first call your supervisor and confirm that he meant it, if his phone is busy keep trying...)

13:06 jcromartie: the point being that bureaucracy is bad?

13:13 somnium: no particular point, just an image of (send secret-agent #(when @im-not-kidding (activate-the-bomb %)))

13:14 fdaoud: somnium: now there's a DSL if I've ever seen one :-)

13:14 mattrepl: it's the difference between being told it's time to leave and being thrown out

13:14 arohner: somnium: sure, but you could have updated information

13:14 (send secret-agent #(when @bad-guys-dont-give-up (activate-the-bomb)))

13:15 blowing up the bomb after surrender is generally considered bad form

13:15 :-)

13:16 somnium: java.lang.Exception "we lost the war because our operatives couldnt phone our destryed headquarters"

13:17 stuartsierra: java.lang.DoomsdayDeviceActivatedException

13:17 arohner: somnium: that

13:17 somnium: that's why you want good defaults

13:18 stuartsierra: (try (launch-attach) (catch java.lang.RogueCommander (abort)))

13:19 somnium: :-)

13:19 ohpauleez: will someone write about how Clojure is capable of not only stopping runaway trains, but saving all of humanity

13:20 stuartsierra: Everyone will be protected by Refs.

13:20 ohpauleez: STM will set you free

13:20 stuartsierra: Resources are allocated fairly to all agents.

13:21 No more mutation.

13:29 ohpauleez: haha

13:31 alexyk: what's the max int again?

13:31 stuartsierra: ,(Integer/MAX)

13:31 clojurebot: java.lang.NoSuchFieldException: MAX

13:31 stuartsierra: ,Integer/MAX_VALUE

13:31 clojurebot: 2147483647

13:31 technomancy: Integer/MAX_VALUE

13:32 alexyk: ah ok

13:32 technomancy: doh, too slow

13:32 stuartsierra: :)

13:32 clojurebot needs a "did you mean ...?" feature :)

13:32 technomancy: it's pretty good at fuzzy matches on keywords

13:32 but not on code. =)

13:33 stuartsierra: yeah

13:35 That's the magical editor everyone wants: your code is wrong, it should be ....

13:39 hiredman: stuartsierra: did you see abi-watch?

13:40 stuartsierra: no

13:40 hiredman: http://www.thelastcitadel.com/lab/abi-watch/1.1.x-1.0.x.diff.html

13:40 http://www.thelastcitadel.com/lab/abi-watch/

13:41 stuartsierra: ok

13:41 hiredman: I haven't tied it all together yet, but it's some scripts that generate diffs of, basically, the various members and types defined in java

13:41 stuartsierra: cool

13:43 hiredman: so in http://www.thelastcitadel.com/lab/abi-watch/master-1.0.x.diff.html you can scroll down and see where the RestFn constructor gained an argument

13:44 stuartsierra: I see

13:46 hiredman: the class files generated by clojure are full of gensyms so doing diffs is difficult

13:47 (possibly impossible)

13:47 stuartsierra: yeah

14:08 hiredman: I wonder how hard it would be to add an interop form to the compiler that allows the direct use of java operators

14:08 (jop + (int 1) (int 2))

14:11 cemerick: that's getting close to what rhickey has called java-in-parens

14:11 though it's probably more like host-in-parens these days

14:24 alexyk: how clojure can exist as a lisp with all that vomit-inducing java underneath, teaming with monsters and reptiles, is amazing

14:24 like "The Matrix"

14:24 ordnungswidrig: aloha

14:24 alexyk: guten tag

14:25 or, guten :tag!

14:28 ordnungswidrig: hehe.

14:29 alexyk: yeah, I was always curious how German programmers handle English tag used everywhere

14:29 except Perl, which blesses things

14:31 ahould be abend too now probably

14:34 ordnungswidrig: when does tag become abend?

14:34 i.e. what hour of the day, roughly

14:34 ordnungswidrig: alexyk: hard to say, I think 6 o'clock would be commonly agreed upon

14:35 alexyk: ok, so it's more like evening than afternoon

14:35 and do you say guten nacht when meeting in the evening, or is it mainly for good bye and good night?

14:36 ordnungswidrig: yes, "gute nacht" is literaly "good night" and only used like you said

14:36 afternoon is "nachmittag" (nach/after mittag/noon)

14:38 alexyk: ok

14:39 so do people say gute nachmittag or guten abend around say 3-4?

14:40 jasapp: what's more important than saying, "Bier bitte."?

14:41 ordnungswidrig: hmm, no, nobody would say "guten nachmittag", it's until about 6-7 that they say "Guten Tag" / "Hallo" . They say "Grüß Gott" mainly southern germany the whole day and "Moin Moin" in the most northern parts.

14:42 alexyk: jasapp: I thought it's "bier schnelle" or something like that :)

14:42 ordnungswidrig: jasapp: "Ein Bier, bitte" would be more polite. And perhaps the kind of Bier you'd like: Lager, Kölsch, Weißbier, Dunkles, Export, Radler or the brand

14:42 jasapp: ahh

14:42 ordnungswidrig: "Schnell, ein Bier" / "A Beer! Quick!"

14:42 jasapp: gotcha, nice.

14:43 alexyk: (schnell (ein 'bier)) ; smoothly steering back into clojure

14:47 ordnungswidrig: anybody used fleetdb yet?

14:59 hiredman: I think something like jop would be needed to turn Numbers.java into numbers.clj

15:00 and it seems like adding a special form would be a good place to start trying to get a handle on the Compiler :D

15:06 somnium: just need to wrap the 220-or-so asm methods in a simple s-expression api :P

15:06 alexyk: what's the single fun for not empty? again

15:06 somnium: seq

15:06 alexyk: right, but for nil?

15:07 somnium: ,(seq nil)

15:07 clojurebot: nil

15:07 alexyk: ,(seq :a)

15:07 clojurebot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Keyword

15:07 alexyk: I need a non-empty test to pass to filter

15:07 without #()

15:08 ordnungswidrig: sigh

15:08 somnium: what does non-empty mean?

15:08 chouser: does protected static on a method mean anything in that package can use it, but other packages can't?

15:08 alexyk: sorry. not-nil would do

15:09 somnium: ,(nil? nil)

15:09 clojurebot: true

15:09 ordnungswidrig: I have a var declared in a lib, say a switch to enable debug tracing. How can I make a client of the lib change the var? With "with-bindings?

15:09 hiredman: somnium: well, most of the asm stuff would be taken care of via the compiler

15:09 _ato: chouser: http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html

15:09 alexyk: duh, I can just extract the damn thing, it will be its own filter

15:09 hiredman: function application is method call

15:10 Ober2: WARNING: JRuby does not support native extensions or the `mkmf' library.

15:10 alexyk: btw I take my hat off to you folks brave enough to brave the java. It's hidden so well!

15:10 hiredman: and there is the . interop form, so I don't know that you would need to wrap that much

15:10 Ober2: oops wrong chan

15:10 alexyk: begone, ruby! do..end!

15:11 somnium: hiredman: youve been playing with java asm havent you? is enough exposed in c.c.compiler to do it with a macro?

15:11 hiredman: I don't know

15:11 I don't understand the compiler

15:12 somnium: doing ,(show c.c.compiler) was rather intimidating

15:12 hiredman: heh

15:12 c.l.compiler

15:13 zaphyr: #<CompilerException java.lang.IllegalStateException: Nested #()s are not allowed (run_stream.clj:26)> ? :(

15:13 hiredman: you can put a #() inside a #()

15:13 chouser: can't

15:13 hiredman: thank you

15:13 chouser: :-)

15:13 zaphyr: lol, got confused there :)

15:14 chouser: _ato: thanks

15:14 zaphyr: thinking about it though, what would % mean? so stands to reason

15:14 ordnungswidrig: hiredman: is there an alternative other than fn for nested #()'s?

15:14 hiredman: uh

15:14 ordnungswidrig: s/'//

15:14 hiredman: no

15:14 ordnungswidrig: perhaps it's good this way

15:17 zaphyr: yeah, after a minor refactor i removed the need for nested #()s, and shortened my expression down by about 50%, so it helped me along in this case.

15:25 cemerick: I'm amazed at what I can do with enlive almost every day

15:36 wlr: cemerick: maybe a nice blog post or three would help us less telepathic users of enlive ;-)

15:37 cemerick: wlr: yeah, it's definitely in the cards. Monday might be a good slack day. :-)

15:37 wlr: cemerick: looking forward to it!

15:41 Mec: ,(.nextDouble java.util.Random.)

15:41 clojurebot: java.lang.ClassNotFoundException: java.util.Random.

15:45 jcromartie: is there a way to attach middleware to every route in a compojure app?

15:45 without naming the handlers?

15:49 also: why is the compojure wiki not written in compojure? :P

15:49 chouser: why is emacs not written in clojure?

15:49 hiredman: rms's shortsightedness

15:50 chouser: heh

15:50 jasapp: wasn't there a group of people that started trying to write emacs in common lisp?

15:50 hiredman: sure

15:50 jasapp: a rather substantial effort, if I remember correctly

15:50 hiredman: yeggie is rewriting it in javascript :P

15:51 chouser: in what he calls javascript

15:54 lpetit: Hi, any ccw user in the room ?

15:54 I guess I already know the answer :-(

15:55 the-kenny: lpetit: What's "ccw"?

15:55 lpetit: ~ccw

15:55 clojurebot: ccw is http://github.com/laurentpetit/ccw

15:55 lpetit: ~counterclockwise

15:55 clojurebot: Counterclockwise aka ccw at http://code.google.com/p/counterclockwise/

15:55 lpetit: eclipse plugin for clojure

15:56 the-kenny: ah

15:57 alexyk: what's the shortest way to filter non-nil values only from a seq?

15:57 (filter <what?> [1 nil 3]) => [1 3]

15:58 lpetit: ,(doc find)

15:58 clojurebot: "([map key]); Returns the map entry for key, or nil if key not present."

15:58 lpetit: ,(doc filter)

15:58 clojurebot: "([pred coll]); Returns a lazy sequence of the items in coll for which (pred item) returns true. pred must be free of side-effects."

15:58 lpetit: identity

15:58 ,(filter identity [nil false :a])

15:58 clojurebot: (:a)

15:58 lpetit: gloups

15:58 alexyk: identity is ok

15:58 lpetit: nope, does not work for false

15:59 somnium: ,(remove nil? [nil false :a])

15:59 clojurebot: (false :a)

15:59 lpetit: thx somnium

15:59 Raynes: somnium: I was two seconds away from pressing enter, you...

15:59 alexyk: I don't expect false

15:59 Raynes: I need to remap my parentheses keys. ;)

15:59 lpetit: nil? is shorter than identity so it's the shortest you were after :-)

15:59 alexyk: Raynes: it's Florida sun :)

16:00 zaphyr: ahh, (remove x y) == (filter (complement x) y)?

16:00 lpetit: ~source remove

16:00 literally, yes

16:00 zaphyr: \o/ :D

16:00 lpetit: :)

16:02 jcromartie: what's the case for false, anyway?

16:02 aside from Java interop

16:03 zaphyr: ,(empty? false)

16:03 clojurebot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Boolean

16:03 chouser: jcromartie: I think that's it.

16:08 alexyk: the beauty of clojure: you think of what a defn should be called, write it down, call it, and it's there

16:08 "Clojure: the core is always there for you"

16:09 * alexyk wonders if core is hardcore and contrib is softcore

16:10 JayM: is there yet a name for someone who programs in Clojure?

16:10 Clojurers?

16:10 Raynes: JayM: I'm Anthony. Does that count?

16:10 :p

16:10 JayM: :)

16:12 alexyk: Raynes: well, I'm not Anthony, so it says nothing of the class :)

16:12 consurers (inverting jure)

16:13 Raynes: We should call them Anthonyers.

16:13 alexyk: clojurassic park rangers

16:13 Raynes: then at least richers

16:16 JayM: in any case, i'm a wannabe, having a hell of a time getting swank-clojure installed

16:16 ELPA doesn't like me

16:16 Raynes: JayM: Even if it errors or something, it might still be installed.

16:17 JayM: Raynes: i keep getting: trying to parse http response code in odd buffer

16:17 Raynes: Oh.

16:17 That's ELPA madness.

16:17 Stab it three times in the chest and move it aside.

16:17 JayM: haha, ok

16:18 might just be something in my config...trying clean now..

16:28 thearthur: how do i (use 'clojure.zip) when it conflicts with the name next in clojure.core?

16:28 hiredman: you don't

16:28 you require it

16:28 thearthur: i want to use zip/next to refer to that

16:28 hiredman: ,(doc require)

16:28 clojurebot: "([& args]); Loads libs, skipping any that are already loaded. Each argument is either a libspec that identifies a lib, a prefix list that identifies multiple libs whose names share a common prefix, or a flag that modifies how all the identified libs are loaded. Use :require in the ns macro in preference to calling this directly. Libs A 'lib' is a named set of resources in classpath whose contents define a library of Cloju

16:29 JayM: bah, manual install it is

16:32 Raynes: thearthur: (ns ans (:require [clojure.zip :as zip]))

16:33 duncanm: i'm having trouble using agents

16:33 if i do this, (def a (agent [])) (send a #(vec 1 2 3))

16:33 eventually, @a will be [1 2 3], right?

16:34 kotarak: duncanm: no. you want (send a #(vector 1 2 3))

16:34 hiredman: neither

16:35 kotarak: ah, yes

16:35 hiredman: the first argment is hte current state of the agent

16:35 kotarak: the state

16:35 (send a #(do % (vector 1 2 3)))

16:35 hiredman: (constantly [1 2 3])

16:36 duncanm: (send a #(constantly [1 2 3]))

16:36 i did that, and a is still []

16:36 hiredman: wait

16:36 kotarak: (await a)

16:37 duncanm: and it stalls

16:37 hiredman: yes

16:37 await waits for the action to run

16:37 duncanm: which should return immediately, shouldn't it?

16:37 it's #(constantly [1 2 3])

16:38 hiredman: it depends on things

16:39 if you are still using the same agent, the agent will have errors from you previous attempts, but send should should throw an exception in that case

16:39 and I am not sure about the behaviour of await on agents with errors

16:39 duncanm: ahh

16:39 Chousuke: um, don't you need (send a (constantly [1 2 3]))

16:39 hiredman: Chousuke: right

16:39 send also uses a fixed size threadpool to run actions

16:40 so if you are sending other things your actions my que up

16:41 duncanm: http://gist.github.com/295146 -- is this a correct usage?

16:41 i dunno if i got the arity right for this: #(calculate-offset %1 file sec %2 %3)

16:41 thearthur: what is the apropriate way to alias the name space clojure.zip to just zip?

16:42 hiredman: duncanm: the first argument to the agent action is always the state of the agent

16:42 chouser: (ns ... (:require [clojure.zip :as zip]))

16:42 Raynes: thearthur: Hiredman and I both told you about 7 minutes ago.

16:43 Chousuke: duncanm: looks correct

16:43 hiredman: and I would use send-off instead of send for anything with a sleep in it

16:43 duncanm: hiredman: okay

16:43 thearthur: what wrong with this (require 'clojure.zip :as zip)

16:44 the-kenny: ,(require '[clojure.zip :as zip])

16:44 clojurebot: nil

16:44 hiredman: thearthur: look at the form with :require that chouser showed you

16:44 what is the difference?

16:44 thearthur: Raynes, I'm looking to do it from the repl with out setting the namespace

16:45 Raynes: thearthur: (require '[clojure.zip :as zip])

16:45 thearthur: Thanks Raynes :)

16:45 Raynes: thearthur: the-kenny got it first. :p

16:46 duncanm: ahh

16:46 i'm getting close

16:46 i still have trouble using condp; i keep on asking the same question without getting how to use it

16:47 hiredman: ,(condp = 6 6 :six 7 :seven)

16:47 clojurebot: :six

16:47 hiredman: ,(condp = 7 6 :six 7 :seven)

16:47 clojurebot: :seven

16:48 duncanm: hiredman: i want to use condp just like cond, but i also want to use :>>

16:48 hiredman: so i don't know what to use for the 'pred'

16:48 hiredman: duncanm: that sounds like a bad idea

16:49 I suggest you just wrap cond in a let

16:49 duncanm: hiredman: so what i can do?

16:49 ahh

16:49 yeah

16:49 let me do that

16:49 hiredman: I will let you do that

16:49 *let*

17:02 alexyk: how do I (use ...) a package but exclude a defn which conflicts?

17:04 the-kenny: alexyk: :exclude?

17:04 s/?/ ?/

17:04 alexyk: ok

17:04 say I successfully did a (use ...) in one ns, and have a conflict in another. Can I refer the old one with some exclusions?

17:07 so if my use is: (use '(incanter core stats charts)), how do I exclude group-by?

17:07 i.e. where do I stick it

17:08 chouser: you want to exclude incanter's group-by, or clojure's?

17:09 alexyk: chouser: I already have clojure's sitting in my ns. I'd drop whichever :)

17:09 if I can choose, it would be nice

17:10 chouser: you can ns-unmap the one that's there (core) and then do what you want.

17:11 alexyk: ah, so it does the use after all, but simply warns about group-by

17:11 that's what I needed

17:11 better it said "warning" or something

17:12 or maybe not...

17:12 it skips the whole unit where the conflict is?

17:26 lygaret: hey y'all could I get help with a question?

17:26 I need to transform a symbol to an equiv string

17:26 like (tostring 'one) => "one"

17:27 jasapp: ,(doc name)

17:27 clojurebot: "([x]); Returns the name String of a symbol or keyword."

17:27 zaphyr: ,(name foo)

17:27 clojurebot: java.lang.Exception: Unable to resolve symbol: foo in this context

17:27 zaphyr: oops.

17:27 lygaret: haha

17:27 zaphyr: ,(name 'one)

17:27 clojurebot: "one"

17:27 hiredman: ,(name 'foo)

17:27 lygaret: Awesome, thanks guys

17:27 clojurebot: "foo"

17:27 hiredman: ,(str 'foo)

17:27 clojurebot: "foo"

17:27 hiredman: ,(.toString 'foo)

17:27 clojurebot: "foo"

17:27 lygaret: I couldn't find that in the docs

17:27 hiredman: ,(prn-str 'foo)

17:27 clojurebot: "foo\n"

17:27 hiredman: ,(pr-str 'foo)

17:27 clojurebot: "foo"

17:28 jasapp: ,(with-out-str (print 'foo))

17:28 clojurebot: "foo"

17:28 zaphyr: %D

17:28 hiredman: ,(format "%s" 'foo)

17:28 clojurebot: "foo"

17:29 zaphyr: hiredman- for all your symbol to string needs :)

17:30 is there a convenient way to check if a sequence is lazy, like printing it without forcing all the elements?

17:31 Chousuke: you can check whether it's a LazySeq, but I think that won't cover all lazy seqs :P

17:32 zaphyr: yeah, i kind of want to see how much has already been realised

17:32 class doesn't give me that

17:33 Chousuke: I don't think there's any way to know that.

17:33 unless you specifically construct a lazy seq that keeps track of its progress

17:33 hiredman: a lazy-seq is still a lazy-seq, even if it has been realized

17:34 zaphyr: yeah. i'm not having a problem right now, it just occured to me in some situations it might be handy to check things are working as you expect

17:34 not in a program, more at the repl

17:35 Raynes: Oh no! I'm being garbage collected!!! Quick, somebody, hold my head!!

17:35 zaphyr: :)

17:35 ghotli_: looking through the docs, can't find this function. how do i create a long list of the same number.

17:35 ie (5 5 5 5 5 5 5)

17:36 zaphyr: ,(take 10 (constantly 5))

17:36 clojurebot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.core$constantly__4704$fn__4706

17:36 chouser: ,(repeat 10 5)

17:36 clojurebot: (5 5 5 5 5 5 5 5 5 5)

17:36 ghotli_: *sigh* wow.

17:37 zaphyr: not constantly

17:37 ghotli_: i'm surprised i didn't just guess repeat

17:37 anyway thanks!

17:37 hiredman: ,(take 5 (iterate (constantly 5)))

17:37 clojurebot: java.lang.IllegalArgumentException: Wrong number of args passed to: core$iterate

17:37 hiredman: ,(take 5 (iterate (constantly 5) 5))

17:37 clojurebot: (5 5 5 5 5)

17:40 zaphyr: ahh, yeah. i got constantly muddled with repeat

17:43 Chousuke: ,(take 5 (repeatedly (constantly 5))) one more way :P

17:43 clojurebot: (5 5 5 5 5)

17:44 zaphyr: throw an identity in there for good measure :)

17:44 chouser: ,(take 10 (iteratate identity 5))

17:44 clojurebot: java.lang.Exception: Unable to resolve symbol: iteratate in this context

17:44 chouser: ,(take 10 (iterate identity 5))

17:44 clojurebot: (5 5 5 5 5 5 5 5 5 5)

17:45 zaphyr: i still can't get over how absolutely cool lazy

17:45 meh. irc client fail. :/

17:45 Chousuke: zaphyr: your sentence wasn't fully realised :P

17:45 zaphyr: :)

17:45 chouser: heh

18:07 ghotli_: how about ripping off the first few items of a seq and returning the rest

18:07 rest will just rip off the first item

18:09 zaphyr: ,(drop 3 '(1 2 3 4 5 6 7))

18:09 clojurebot: (4 5 6 7)

18:09 dakrone: ghotli_: use (drop ..)

18:09 ghotli_: wonderful. thanks.

18:10 zaphyr: there's also drop-while which takes a predicate instead of a count

18:11 billsmithaustin: ,(println "hello world")

18:11 clojurebot: hello world

18:14 zaphyr: hmm. why is there an nthnext when there is a drop?

18:14 symmetry with nth?

18:15 hiredman: ,(doc rest)

18:15 clojurebot: "([coll]); Returns a possibly empty seq of the items after the first. Calls seq on its argument."

18:15 hiredman: ,(doc next)

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

18:15 zaphyr: ahh

18:15 thanks

18:34 Raynes: hiredman: You should add an equivalent of lambdabot's @faq. clojurebot: Can Clojure <insert something here>?, and clojurebot should reply with "Yes! Clojure can do that!".

18:34 Something like that.

18:34 hiredman: clojurebot: can clojure do so and so?

18:34 clojurebot: excusez-moi

18:35 zaphyr: clojurebot: can clojure make the tea?

18:35 clojurebot: That is the one thing Clojure can not do.

18:35 zaphyr: why not?

18:36 hiredman: it's complicated

18:36 technomancy: someone please write a HTCPCP module

18:36 it's not tea, but it's a step in the right direction

18:37 zaphyr: :)

18:37 * neotyk 418 I'm a teapot

18:38 technomancy: rfc2324 is always good for a laugh.

18:38 neotyk: true

18:39 is following true statement: c.c.http.agent is not utilizing NIO?

18:40 ~def c.c.http.agent

18:40 zaphyr: hmm, i need a combination of reduce and split-while- sort of like "split at the point the sum of the head is greater than", is there a neat trick i can use to do this?

18:41 Raynes: Why can't java.io.File's mkdir/mkdirs method make directories with dots at the beginning? It appears to fail silently. Is it some security crap or something?

18:43 hiredman: works for me

18:46 Raynes: Hrm. It works for me now...

18:46 My code must be constructing the File wrong.

18:47 Oh, I see. Doesn't like a trailing forward slash at the end.

18:47 hiredman: or you are using a relative pathname with no idea of where your working directory is

18:48 Raynes: Or it doesn't like a trailing forward slash at the end.

18:48 Which is the problem. :p

19:01 neotyk: ,(let [f (partial (fn [a b] (str a " " b)) "fixed")] (println (f "one")) (println (f "two")))

19:01 clojurebot: fixed one fixed two

19:01 neotyk: every day Clojure brings something new

19:01 this is great

19:03 mabes: I've seen # used in macros, but I can't seem to find documentation on what that does, any pointers? (i.e. `(defn ~fn-name [options#]... )

19:03 tcrayford: it makes a gensym

19:03 hiredman: mabes: it it gensyms inside syntax quoted forms

19:03 ,`a#

19:03 clojurebot: a__4961__auto__

19:04 tcrayford: ,(doc gensym

19:04 clojurebot: EOF while reading

19:04 tcrayford: ,(doc gensym)

19:04 clojurebot: "([] [prefix-string]); Returns a new symbol with a unique name. If a prefix string is supplied, the name is prefix# where # is some unique number. If prefix is not supplied, the prefix is 'G__'."

19:04 mabes: ahh, thanks

19:04 tcrayford: which prevents variable capture. See chapter 9 of on lisp

19:04 Raynes: http://java.ociweb.com/mark/clojure/article.html#Macros

19:05 mabes: great resources, thanks all

19:20 herdrick: hi folks - what is the deal with Incanter shipping with all it's dependencies, including Clojure?

19:20 i don't see an easy way to remove it's version of clojure from Incanter

19:21 as it ships Clojure in the same jar file that it puts Colt and many other things in

19:22 tcrayford: use lein instead then?

19:22 Raynes: What Mr. Ford said.

19:22 herdrick: well, i'm not using lein yet. also, would that work?

19:23 wouldn't lein just install the same jars?

19:23 the problem is that things I need and things i want to avoid are in the same jar

19:23 tcrayford: lein will pull all your dependancies as needed

19:24 herdrick: so it will start with a dependency-less Incanter and then get deps as needed?

19:25 so where is this dependency-less version of Incanter

19:25 ?

19:25 tcrayford: it'll grab all of incanters deps when you run `lein deps`

19:25 herdrick: i don't want all it's deps

19:25 ex. Clojure

19:25 tcrayford: how do you propose running it without its deps?

19:26 herdrick: i already have the Clojure installed that i want

19:26 tcrayford: does incanter ship with an old version?

19:26 herdrick: i'm saying that Incanter seems to do overkill on the deps

19:26 not sure, i guess it might be ok

19:26 i sure don't like having multiple versions of Clojure hanging around tho

19:27 tcrayford: hah

19:27 it doesn't make a huge amount of difference unless you want to be using super cutting edge features

19:27 at least as far as I've found

19:27 herdrick: hmm, ok

19:27 btw i still don't think lein would help here

19:28 but you're probably right that the thing to do is just use incanter's clojure

19:28 even though it may break something

19:28 sigh

19:28 zaphyr: hmm. surely there is a way to avoid this monstrosity? http://paste.lisp.org/display/94395

19:29 tcrayford: zaphyr: what does that do?

19:30 zaphyr: it's like reduce and map

19:30 hiredman: ,(doc reductions)

19:30 clojurebot: "([f coll] [f init coll]); Returns a lazy seq of the intermediate values of the reduction (as per reduce) of coll by f, starting with init."

19:30 zaphyr: aha! thanks :D

19:30 hiredman: ,`reductions

19:30 clojurebot: clojure.contrib.seq-utils/reductions

19:43 wtetzner_: i'm trying to use jvisualvm to profile my program, but it says it can't profile when class sharing is turned on

19:43 So i set (setq swank-clojure-extra-vm-args '("-Xshare:off")), and jvisualvm shows that the -Xshare:off parameter was used, but it still says that sharing is turned on

19:43 has anyone else had a problem like this?

19:44 hiredman: is jvisualvm written in java? maybe it needs sharing turned off for its vm

19:45 wtetzner_: i'll try that

19:46 no, it still tells me that class sharing is enabled

19:47 is there anything in swank-clojure that would cause sharing to be turned on, even though i added it to the swank-clojure-extra-vm-args?

19:53 Mec: if add-classpath is deprecated, what should be used?

19:56 hiredman: it's complicated, but as of now there is no clear replacement

20:04 Mec: didnt seem to work anyway

20:24 Is there a way to add a directory of clj files without having to call load-file on each?

20:32 chouser: the order of loading them doesn't matter?

20:32 anyway, no, I know of no such thing.

20:32 tcrayford: you can just (map load-file (file-seq dir))

20:33 oops, laziness

20:38 alexyk: to create a catch-all clause for cond, do we use true ?

20:39 tcrayford: :else

20:39 alexyk: tcrayford: but any non-nil will do like true, right

20:39 tcrayford: try it at a repl

20:39 using else is a standard though

20:40 Mec: I'm trying to get the Programming Clojure sample code to load in a real repl, looking at the .bat file they use i dont see any explicit calls to the .clj files so how are they loading?

20:40 tcrayford: they load on the java classpath

20:40 iirc

20:41 alexyk: ,(let [x 0] (cond (< x 0) (print "neg") (> x 0) (print "pos") true (print "zero")))

20:41 clojurebot: zero

20:55 Mec: this is a nightmare

21:19 is there a way to see the classpath for a currently running repl?

21:20 hiredman: clojurebot: classpath?

21:20 clojurebot: classpath is (System/getProperty "java.class.path")

21:22 Mec: thanks

21:26 alexyk: is there an idiom to shorten this:

21:26 (if twice-wider? (* up 2) up)

21:27 ok am back, looking for a shorter idiom than: (if twice-wider? (* up 2) up)

21:27 specifically for tomoj: what's shorter than (if twice-wider? (* up 2) up)?

21:29 tomoj: (* up (if twice-wider? 2 1)) is a tiny bit shorter :(

21:30 but I'd prefer yours

21:32 something like (-?> up twice-wider? (* 2)) seems to get at the idea better

21:32 but I don't like that syntax

21:32 and -?> is probably a bad name for it

21:34 oh, and -?> is already taken in contrib

21:34 alexyk: tomoj: -?> fits well here in fact

21:36 tomoj: except, I dunno if you'd want to have more than one form to conditionally thread through

21:36 if so you'd certainly want to change the syntax, I think..

21:51 alexyk: yay! chouser's back!

21:52 chouser: huh. 6 minutes this time.

21:53 huh. 6 minutes this time.

21:55 alexyk: looks like an ice-covered internet

22:06 liebke: ping

22:06 liebke: hey

22:07 alexyk: liebke: is there an option to set size on charts?

22:07 liebke: yes

22:07 alexyk: e.g., 5cm x 5cm?

22:07 liebke: pixels, not cm

22:07 alexyk: is it png only?

22:07 I need PDF for the paper

22:08 or a way to control size in cm's

22:08 liebke: jfreechart doesn't do pdf unfortunately

22:08 alexyk: oh well

22:08 copy-paste into R then :(

22:09 wonder though png will be eaten by latex

22:09 TheBusby: liebke: what was the trick to dictate pixel size again? And would that impact the number ,er keys?, that appear legibly at the bottom of the chart?

22:10 alexyk: liebke: btw, vnc works like a charm with incanter

22:10 Mec: I'm using the following in my .emacs, but it doesnt seem to be doing anything: (setq swank-clojure-extra-classpaths (list "F:/Tools/programming-clojure/code"))

22:10 liebke: in the save function, it's :width and :height

22:10 alexyk: graphs are safe in the cloud

22:10 liebke: alexyk: great

22:10 TheBusby: ahh save...

22:10 alexyk: liebke: so any plans for pdf/eps? what can be done?

22:11 liebke: TheBusby: they also can be used in the view function

22:11 TheBusby: thank you, didn't think to check save/view

22:11 liebke: alexyk: I looked into it once, nothing clean for generating pdfs at the time

22:11 alexyk: it's probably a deep flas, because pdf needs vector graphics... does it mean jfreecharts is raster only?

22:12 flaw

22:12 liebke: alexyk: no, they appear to be vector

22:12 alexyk: cemerick has a pdf business

22:13 let's enroll cemerick in his pro bono time :)

22:13 liebke: alexyk: there is a lib that will do it with jfreechart, but it was too many additional dependencies, and there might have been some licensing issues (can't remember)

22:13 alexyk: liebke: ok, so not so bad

22:15 tomoj: I kind of want to auto-require repl-utils :as repl on my slime repls

22:16 but then I worry someday I'll run into a conflict :(

22:16 alexyk: tomoj: live for today! sort the tmrw conflicts tmrw

22:17 TheBusby: any hints on how I could keep the X-axis legible for a line-chart?

22:17 tomoj: guess I could make a keybinding that does it with a C-u switch for specifying the :as

22:20 liebke: TheBusby: why are they illegible?

22:20 TheBusby: liebke: for 40 points, the text ends up being too small and they get turned into dots

22:20 liebke: make the chart wider

22:21 TheBusby: yeah, but around 1900x1200 it becomes the limit though

22:21 I noticed the y-axis just used a sequence of numeric values

22:22 Mec: Is anyone familiar with adding classpaths to clojurebox?

22:22 TheBusby: any way to do something similar for the x-axis? or is that a different kind of chart?

22:23 liebke: do you want a line-chart or an xy-plot? are x and y both continuous data?

22:24 if one set of values is categorical you can create a 'horizontal' bar-chart (:vertical false), which makes it easier to see the labels when you have lots of categories

22:25 TheBusby: trying xy-plot now

22:26 neither x or y is categorical, so it sounds like I'd be better servered by the xy-plot

22:26 liebke: yeah, use xy-plot

22:26 line-chart is just a different skin on a bar-chart

22:28 TheBusby: liebke: perfect, much thanks for both incanter and your help!

22:29 liebke: TheBusby: you're welcome, good luck

22:30 dnolen: Mec: I don't know if there are many Windows Clojurians on channel. Did you try the mailing list?

22:31 Mec: I'm following a set of instructions from the mailing list

22:34 success finally

22:41 tomoj: I was so happy I got an assignment at work where I can use clojure

22:42 now I'm sitting here editing a 500 line xml file

23:05 hiredman: anyone have adivce to give for clojure.lang.Compiler?

23:07 brweber2: anyone have pointers to simple examples of using clojure.zip?

23:07 I'm looking for more examples of zippers

23:09 herdrick: brweber2: I support your quest

23:09 i'd like to see that too

23:10 brweber2: herdrick I seem to keep finding the sample trivial example and nothing else. I'm really interested in using zippers, not reading academic papers at this point :)

23:12 herdrick: brweber2: yeah

23:14 hiredman: java.lang.VerifyError: (class: user$eval__1, method: invoke signature: ()Ljava/lang/Object;) Expecting to find integer on stack (NO_SOURCE_FILE:0)

23:14 :(

23:15 tomoj: brweber2: in general? or you have some specific use in mind?

23:16 brweber2: tomoj I'm looking for general examples. I'm hoping to implement something like a simple namespace tree...

23:17 tomoj: oh, I never built my own zipper, just used xml-zip

23:39 hiredman: ser=> (jop + (int 2) (int 1))

23:39 3

23:39 :D

23:39 * hiredman wins

23:44 hiredman: beautiful, compiles to an iadd

Logging service provided by n01se.net