#clojure log - Oct 02 2010

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

1:28 Bahman: Hi all!

1:29 TeXnomancy: allo

1:29 salut

1:30 sunt eu, un haiduc 𝅘𝅥𝅮

1:31 amalloy: buenas mañana

2:13 bobo_: hm, cake autotest doesnt seem to always get the latest file when running tests?

2:14 it detects my save, but says the error is still there

2:14 lein doesnt agree

2:14 and restarting autotest and it says no errors

2:14 anyone else seen this? or is it just me

2:16 TeXnomancy: bobo_: probably getting slimed?

2:16 got some leftover state

2:16 lein test is meant for a sanity check, which is why it always starts a new JVM

2:16 it's pretty common for persistent JVMs like swank or cake to get leftover state that confuses things

2:17 bobo_: i dont like it :-/

2:17 almost faster to run lein aswell

2:18 TeXnomancy: you should always run tests with a fresh JVM before you check in

2:18 but there's totally a need for in-JVM tests too; that's what I use clojure-test-mode for

2:19 bobo_: yeh, its kinda pointless if it doesnt work =)

2:20 il give clojure-test-mode a try

2:22 TeXnomancy: the sweet thing about clojure-test-mode is that it highlights the failures inside the test buffer

2:23 nice instant-feedback

2:23 but restarting your cake JVM would probably un-wedge it too

2:25 bobo_: yeh, but it happens about 20% of every save

2:44 tomoj: anyone know how many attendees the jvm language summit gets?

3:31 amalloy: i need to split a bunch of objects into sets, and would like it to be easy/fast to (a) see what objects are in a set, and (b) what set an object is in. it seems like immutability makes this easy task pretty hard; is there something i'm missing?

3:58 quizme: what's the version of clojure we should be using these days?

3:58 clojure-1.2.0 ?

3:59 i'm reading a tutorial that references clojure-1.2.0-beta1

3:59 tomoj: 1.2.0 is good

4:00 1.3.0-alpha1 is out

4:00 quizme: so 1.2.0 is "production ready" whatever that means ?

4:01 anyway thanks i'll go with 1.2.0

4:01 tomoj: it's stable and kinda new

4:24 amalloy: quizme: i'm using 1.2.0 and i'm happy with it

4:24 quizme: amalloy thanks

4:25 i'm doing the ring tutorial

4:25 http://pastie.org/1194970

4:25 but i'm getting : java.lang.Exception: Unable to resolve symbol: header in this context (core.clj:15)

4:25 cuz i'm trying to use the header function

4:25 in ring.util.response

4:26 how can i use that function ?

4:26 i tried ring.util.reponse/header but that didn't work: java.lang.Exception: No such var: ring.util.response/header (core.clj:15)

4:28 and when I do "lein repl" now, it says it's listening on localhost:X where X is an integer. It didn't do that before.

4:29 so i can telnet to it now. what's the advantage of that ?

4:37 raek: quizme: first, have you added ring to you project.clj?

4:37 quizme: raek yes

4:38 http://pastie.org/1194993

4:38 raek: http://pastie.org/1194993

4:40 raek: try with the 0.3.1 version

4:40 quizme: raek: ok.

4:43 raek: http://pastie.org/1194995

4:43 raek: i did lein clean; lein deps; lein repl; and got that

4:44 raek: strange

4:44 do you have any files in classes/?

4:44 if so, delete them

4:44 quizme: 'header' was not in the example, but in the docs, right?

4:44 quizme: raek: it's empty

4:45 raek: check that the lib/ dir is empty too

4:45 quizme: raek: yeah, it wasn't in the tutorial. I added it becaue I want to modify the headers.

4:45 raek: lib is full of stuff

4:45 raek: so, it was probably added after 0.2.0

4:45 ok, delete all that

4:45 quizme: raek: ok.... so it's not my syntax i guess

4:45 raek: no, just lib versions, I think

4:46 quizme: ok i removed the stuff from my lib/*

4:46 now doing lein deps

4:46 raek: nothing strange with your code

4:46 strange, I thought lein clean should clear the lib/ dir

4:46 quizme: raek ok good thanks

4:47 i upgraded from an older lein version

4:47 i'm on lein 1.3.1 i think

4:47 http://pastie.org/1194997

4:48 so i did lein deps

4:48 and it seems to be copying cached versions of the jars

4:48 to lib/

4:48 amalloy: quizme: blow away ~/.m2?

4:48 that's where it keeps the cache

4:48 raek: but the different versions are separate jars

4:48 I think you had both versions in lib/ before

4:48 quizme: raek yeah

4:49 amalloy: i blew them away last night, so they're pretty fresh

4:49 raek: ok hope so let's try...

4:49 i'm getting that big long stack trace again

4:50 maybe i did something funky with my classpath ?

4:50 http://pastie.org/1195002 <-- the stack trace

4:51 i thought lein handles the classpath issues for you

4:52 raek: yes, it does

4:52 this is some weird errors with strange jars

4:52 which java version do you run?

4:52 java -version

4:54 quizme: java version "1.6.0_20"

4:54 Java(TM) SE Runtime Environment (build 1.6.0_20-b02-279-10M3065)

4:54 Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01-279, mixed mode)

4:54 raek: youlc you paste your current project.clj?

4:54 looks good

4:54 these kind of errors can be the result of using conflicting versions of libs

4:55 quizme: http://www.pastie.org/1195006

4:55 raek: for example clojure 1.2 with contrib 1.1

4:55 hrm, use clojure 1.20 instead

4:55 quizme: ok

4:55 raek: *1.2.0

4:56 that *should* work since I used the same libs last night...

4:56 quizme: i did lein clean

4:56 but it's not removing the contents of lib/

4:56 raek: bad lein...

4:56 delete all lib/*

4:57 quizme: ok

4:57 repl started

4:57 it says listening on localhost:46962

4:57 does that mean i should telnet to it?

4:57 or should i just use it at the prompt

4:57 raek: you dont' have to

4:57 you can use both

4:58 the repl server is just an extra

4:58 quizme: i did this

4:58 raek: haven't used it myself

4:58 quizme: (use 'ring-tutorial.core)

4:58 but it's just hanging there.

4:58 it says

4:58 nil

4:58 then hangs

4:58 i can hit enter

4:58 raek: try evaluating 1

4:58 quizme: but i'm not getting the user=> prompt

4:58 oh yeah

4:58 it evaluated

4:58 raek: sometimes, I have seen that the prompt doesn't appear after the ifrst command

4:58 quizme: ^^;

4:59 ok

4:59 raek: thought that was a temporary bug...

4:59 quizme: seems to be ok

4:59 lemme try to boot

4:59 raek: I mostly use slime

4:59 quizme: booted

4:59 thanks

4:59 raek: I should probably create a ticket for thay

4:59 quizme: let's see if the header was modified

4:59 raek: np

5:01 quizme: raek thanks a lot for your help. I think i got it from here. Cheers!

5:01 i'm out...

5:41 ldhanson2: I have a sorted-set (of vectors, which appears to sort by the first element of each vector, which is what I want). I do a 'replace' on it, but I get back a LazySeq which is no longer sorted. how do I retain the sorted-ness of this set across a 'replace'?

5:43 amalloy: ,(into (sorted-set) (map inc (range 5)))

5:43 clojurebot: #{1 2 3 4 5}

5:43 amalloy: ldhanson2: ^^

5:44 not exactly elegant, but it works :P

5:45 but i'm off to bed now, so someone else will have to tell you a better way

5:46 hoeck: ,(-> (sorted-set [3 2] [1 2 3] [4]) (disj [3 2]) (conj [3 2 1 0]))

5:46 clojurebot: #{[4] [1 2 3] [3 2 1 0]}

5:46 hoeck: ldhanson2: to me it appears vectors in a sorted set are sorted by their length

5:47 ldhanson2: using disj and conj on a sorted set will maintain its sortedness

5:48 ldhanson2: great, i'll try that

5:48 hoeck: ,(sorted-set-by #(< (first %1) (first %2)) [3 2] [1 2 3] [4])

5:48 clojurebot: #{[1 2 3] [3 2] [4]}

5:49 hoeck: ldhanson2: ^ is a set sorted by the first element of the contained vectors

5:50 ldhanson2: perfect. the behavior i was seeing must have been coincidental

5:50 hoeck: ,(sorted-set-by #(< (nth %1 0 0) (nth %2 0 0)) [3 2] [] [4])

5:50 clojurebot: #{[] [3 2] [4]}

5:51 hoeck: ldhanson2: ^ that one is actually better as it also handles [] and nil

5:52 ldhanson2: excellent

5:55 related question: i'm writing a unit test to demonstrate my assumption about a set's sort order. how can i assert that the ordering of two sets is the same?

6:08 hoeck: ldhanson2: you could check wether they have the same comparator

6:09 or do sth. like http://gist.github.com/607516

6:12 maybe additionally check each set being (sorted? s)

6:20 raek: I think it simply keeps them sorted lexigraphically (like words of letters are sorted: if prefix is the same, sort by next letter. empty string is sorted before any other letter)

6:23 disregard that... I found an counterexample:

6:23 ,(sorted-set [2 1] [3])

6:23 clojurebot: #{[3] [2 1]}

7:13 opqdonut: is clojure useable on Android?

7:14 oh, there's clj-android, sweet

7:16 octe: if i have one namespace with a (def foo "foo") in it

7:16 and in another namespace do

7:17 (ns lol (:require [first.ns :as first]))

7:17 shouldn't i be able to access foo as first/foo?

7:18 hoeck: octe: right, you should

7:18 maybe a typo, does first.ns/foo work?

7:22 octe: nope, it does not

7:26 hoeck: no such var exception or a class not found ex. ?

7:27 octe: no such var

7:27 could it be because there's a circular dependency?

7:29 hoeck: not shure but I think you get a different error, unknown namespace error or so

7:29 octe: slime can complete symbols in the namespace

7:30 hoeck: and when you do a (require 'first.ns :reload) ?

7:30 octe: o such var

7:30 :(

7:33 i refactored it instead

7:35 hoeck: octe: then it was that circular dep :)

7:36 octe: yeah

8:38 AWizzArd: ~seen rhickey

8:38 clojurebot: rhickey was last seen quiting IRC, 2029 minutes ago

8:38 AWizzArd: ,(/ 2029 60.0)

8:38 clojurebot: 33.81666666666667

8:38 AWizzArd: ,*1

8:38 clojurebot: java.lang.IllegalStateException: Var clojure.core/*1 is unbound.

9:51 webus: hi to all

9:52 what do you think about literate programming ?

11:26 TeXnoman`: raek: the prompt flushing bug was fixed just last night

11:27 octe: there's a patch in to detect circular dependencies with a better error message: http://www.assembla.com/spaces/clojure/tickets/8-gc-issue-3-%09re-enable-detection-of-circular-loads

13:42 LauJensen: Has anybody had problems with (with-session) in converting a Jetty app to a Tomcat servlet?

13:54 AWizzArd: My Clojure serialization lib is using recursing to serialize nested objects. This can possibly run into stack overflows. How often do you work in practice with objects that have more than a few ten thousand levels of nesting, and then want to save such things?

13:57 LauJensen: Never...

13:58 kzar: So it's been a while since I played with Clojure, I'm trying to install the latest versions of everything and get it working with Emacs again. Last time I set it all up I used ELPA and it worked really well but this time I'm having problems, is ELPA still the way to go?

13:58 AWizzArd: LauJensen: yes, i also don't have that

13:58 mrBliss: kzar: yes

14:00 kzar: mrBliss: Which guide is the best to follow? I've tried a few and I haven't had swank working. I was hoping to get to the point where M-x slime launches it all and M-x slime connect lets me connect to one that's already running

14:01 LauJensen: kzar: Im having some trouble with clojure 1.3, so make sure you stay away from that while experimenting

14:02 AWizzArd: LauJensen: what kind of trouble?

14:02 LauJensen: AWizzArd: The kind where lein swank wont even start

14:02 kzar: LauJensen: OK, I was trying to get it working with 1.2

14:02 mrBliss: kzar: don't know any recent ones: but I usually install clojure-mode, slime and slime-repl from ELPA

14:02 AWizzArd: I found a new number bug in it, I should update an issue about it

14:02 mrBliss: kzar: If you want to use M-x slime, maybe you should try installing only swank-clojure

14:03 kzar: I've heard that it installs slime etc for you (haven't tried it myself)

14:03 kzar: I get "java.lang.Exception: Unable to resolve symbol: progn in this context (NO_SOURCE_FILE:1)" when I do M-x slime and slime keeps trying to connect until I do a M-x slime-abort-connection

14:08 LauJensen: progn? Are you on Emacs 21 or something?

14:09 mrBliss: kzar: you're trying to execute Elisp code in Clojure

14:12 kzar: mrBliss: Hmm I don't get how, I just typed M-x slime

14:12 LauJensen: No 23

14:13 LauJensen: ok. mrBliss is right, you're calling elisp in java. Im so numb to stacktraces now I apparantly dont even see them anymore :)

14:14 mrBliss: kzar: What did you install?

14:14 kzar: Oh here's something: (progn (load "/home/kzar/.emacs.d/elpa/slime-20100404/swank-loader.lisp" :verbose t) (funcall (read-from-string "swank-loader:init")) (funcall (read-from-string "swank:start-server") "/tmp/slime.5733" :coding-system "iso-latin-1-unix")) that's at the start of the *inferior-lisp* buffer

14:16 mrBliss: I deleted ~/.emacs.d/ and then I installed elpa and using that clojure-mode and swank-clojure I think

14:17 what's your inferior-lisp-program set to?

14:18 mrBliss: kzar: can you check if slime and slime-repl were automatically installed? I stopped using swank-clojure from ELPA a while ago, so my inferior-lisp-program is actually "lisp"

14:20 kzar: ok inside ~/.emacs.d/elpa/ I see archive-contents, builtin-packages, clojure-mode-1.7.1, slime-20100404 package.el, slime-repl-20100404

14:20 mrBliss: kzar: looks fine. I use cljr (playing with clojure) or lein (doing a project), so I never use M-x slime, always M-x slime-connect. Actually I have some elisp that does this for me (M-x lein-swank and M-x cljr-swank)

14:23 kzar: mrBliss: Good idea, although if I use M-x slime-connect I'm not sure how to start the server because lein swank doesn't work anymore

14:24 mrBliss: kzar: make sure you have [swank-clojure "1.2.1"] listed under :dev-dependencies and do a 'lein deps' in the project folder

14:33 LauJensen: mrBliss: Do you use swank-clojure 1.2.1 with clojure-1.3.0-master-sNAPSHOT?

14:33 kzar: brb

14:35 mrBliss: LauJensen: no, I haven't tried the 1.3 snapshots yet, still using 1.2 until beta1

14:36 LauJensen: k

14:38 mrBliss: I'd like to see a new release of swank-clojure though, I've seen many improvements in my github notifications since 1.2.1.

14:38 kzar: OK M-x slime-connect is working now, thanks for the help. In the end I made a project called scratch and just use that to launch lein swank. In a way it's a shame you have to make a project to do that. I made a script to load that project but for some reason even though I've set inferior-lisp-program to run it and port 4005 is opened slime never manages to connect. But at least running the script from a shell and the

14:38 n doing slime-connect isn't too bad

14:40 LauJensen: kzar: some people actually prefer that

14:40 mrBliss: kzar: I open a file of the project, M-x lein-swank and voila a REPL for my project. http://github.com/mrBliss/dotfiles/blob/master/.emacs.d/clojure.el#L79 The same for cljr-swank, because cljr actually is a leiningen project.

14:40 kzar: LauJensen: Yea, me too sometimes but it's crap to be forced into it

14:41 LauJensen: ah nice mrBliss, love your elisp-fu

14:41 kzar: mrBliss: Cool thanks for sharing

14:42 mrBliss: I can't take credit for everything, there was some copy-pasting involved ;-)

14:43 LauJensen: mrBliss: There always is

14:48 raek: kzar: cljr is just that... a global scratch project

14:52 kzar: raek: heh yea, I guess that's the problem / appeal heh

14:56 mrBliss: (gonna see a movie now bbl)

14:56 kzar: cya thanks for the help

15:07 If you want to add a dependency to a lein project but you have no idea which version of the dependency to use what would you do?

15:08 LauJensen: Use the latest

15:10 How does the Ring Session Middleware work with Tomcat ?

15:14 raek: kzar: check its project.clj at github/other hosting

15:24 LauJensen: Is the memory-store not compatible with Tomcats container model ?

15:34 tomoj: hmm, why wouldn't it be?

15:34 just an atom

15:35 LauJensen: It is. My problem has something to do with Moustaches middle-ware strategy

15:35 tomoj: (I'm actually asking, not trying to answer your question.. I dunno shit about tomcat)

15:35 isn't moustaches middleware strategy the same as anything else's?

15:35 LauJensen: tomoj: AFAIK its the only one which has true nesting of routes and middle-wares

15:36 (app ["app2"] (app ["app3"] (app middleware1 "handler1-app3")....

15:36 tomoj: moustache dsl got be all confused for a while

15:36 s/be/me

15:36 LauJensen: oh?

15:36 tomoj: e.g. the syntax file seems to suggest you can return a raw response map

15:37 but this doesn't seem to be possible

15:37 well, not from directly in app I mean

15:37 LauJensen: You can

15:37 I mean, handlers are functions, but those functions can returns maps

15:37 [""] (constantly {:body "Hello"})

15:37 tomoj: I guess constantly would work

15:37 heh, yeah

15:38 I always ended up separating out into named functions which bugged me

15:38 LauJensen: Oh, I like that

15:38 Only for very small apps do you want to keep it inline

15:38 imo

15:38 line

15:38 [""] render-front-page

15:38 ["login"] render-login-page

15:38 and so on

15:38 looks nice

15:41 tomoj: have you abstracted away from a standard set of "REST-ful" endpoints yet?

15:42 LauJensen: No - Which standard sets are you thinking of ?

15:43 tomoj: whichever one you happen to use

15:43 e.g. we use GET /resource, GET /resource/id, POST /resource, PUT /resource/id, ....

15:44 I was using compojure, but didn't really see any good opportunities for abstraction even though I still felt like I was writing boilerplate

15:44 LauJensen: I didn't abstract from a standard set, but I did mold it into something which made sense for the app

15:45 raek: tomoj: [""] [{:body "Hello"}]

15:46 tomoj: raek: huh

15:46 raek: note the extra square brackets

15:46 tomoj: cool

15:46 raek: otherwise, it's a method dispatch map

15:46 tomoj: what do the square brackets mean there?

15:46 raek: nested app

15:46 tomoj: I see

15:46 raek: raw response maps cannot be the RHS of a route

15:47 tomoj: right

15:47 http://moustache.cgrand.net/syntax.html says differently though

15:47 afaik

15:48 well

15:48 raek: handler-main can be a sequence of route + shorthand-or-handler

15:48 or a literal response map

15:48 tomoj: I guess if that's EBNF the parse with a literal response will just be ambiguous?

15:48 raek: shorthand-or-handler can be a method dispatch map

15:48 tomoj: and the actual implementation always chooses method-dispatch

15:49 raek: well, no. at the shorthand-or-handler position, maps always mean method dispatch

15:49 tomoj: oh

15:49 so I just misread the grammar

15:49 raek: it's tricky to read...

15:49 arohner: is there a way to tell maven to download and install a single file, from the command line?

15:50 raek: it utilizes maps and vectors in any way possible

15:50 tomoj: how do we tell the difference between a method-dispatch and a literal response map at handler-main?

15:50 raek: a method dispatch map will always be preceded by a route

15:50 tomoj: raek: successfully, you think? or does it just get confusing? maybe I just didn't stick with it long enough

15:51 oh, method-dispatch isn't a map, I see

15:51 just the innards of the map

15:51 thanks!

15:52 raek: oh, I misread the synatx too... (in another way) :-)

15:53 LauJensen: mispelled it as well :)

15:54 raek: ah, no. it seems that my useage of method dispatch was correct after all in my case: "Besides when the right-hand form is a method dispatch without middlewares you can write the form as a map"

15:54 tomoj: LauJensen: you find app forms to be easy to read and write?

15:55 raek: handler-main -> method-dispatch | (route shorthand-or-handler)+ | ...

15:55 shorthand-or-handler -> {method-dispatch} | ...

15:56 so both [""] [:get ...] and [""] {:get ...} are allowed...

15:57 tomoj: cool

15:58 raek: the routing syntax of moustache migth be complex, but at least it has a formal definition

15:59 LauJensen: sorry, "might"

16:04 tomoj: https://gist.github.com/655c34875e3aef2afd9c O_o

16:04 this is like the stuff in the recent "clojure faster than machine code?" post

16:04 LauJensen: tomoj: Yea. For both Moustache and Enlive the experience was the same: Took a little time to understand the system, but once you get it you dont want to change a thing

16:05 (well, there is a couple of things)

16:05 But they are really brilliantly put together and easy/intuitive to use once you understand them

16:08 tomoj: LauJensen: ok

16:08 I will try it again sometime

16:13 amalloy: tomoj: where did that gist come from? it's absurd

16:14 tomoj: amalloy: it's from a minecraft 3d cave explorer called minecraft-xray

16:14 LauJensen: tomoj: man thats horrible lisp code

16:15 tomoj: I think it's doing something like this http://www.learningclojure.com/2010/09/clojure-faster-than-machine-code.html

16:15 I don't really understand that post yet

16:16 I feel like I have created a similar monster

16:16 * LauJensen hides in Emacs with Moustache and Enlive

16:17 LauJensen: tomoj: You should ask Christophe what he thinks about pre-mature optimization if you ever get the chance :)

16:17 tomoj: https://gist.github.com/bfe2264c4e44b164a3c5

16:17 LauJensen: hehe

16:17 tomoj: the macro parser unrolls the dsl into a giant case statement with the entire code for parsing each packet type unrolled

16:18 so I've got all these ~'data-in everywhere

16:18 ninjudd: bobo_: cake test -r will force a restart

16:18 LauJensen: tomoj: You writing a game ?

16:18 tomoj: because the parse code for each packet type is just stored as a literal map

16:18 no...

16:18 the game already exists (minecraft)

16:18 I am just trying to interoperate

16:19 bobo_: ninjudd: but i want autotest

16:19 LauJensen: oh ok

16:19 tomoj: it's this binary format where the first byte you read specifies the packet type, and each packet type has basically a list of java types to read out of a datainput stream

16:20 but sometimes the length of one field will depend on the value of a previous field

16:20 ninjudd: bobo_: working on integrating lazytest which should fix the problem

16:20 bobo_: ninjudd: ah, nice

16:20 tomoj: so I had to unroll the field parsing to let statements

16:21 https://gist.github.com/fba67c111138cb9e938b here's the macros

16:21 can you tell it's a monster just by looking at it?

16:22 I have a feeling there is a much simpler and more effective way to do this, I just stumbled through making this until I found something that worked

16:24 bobo_: ninjudd: btw, when does it start a new vm? when i use cake from another terminal? i noticed earlier i suddenly had 5 jvm's running. and my computer was out of ram :-)

16:26 amalloy: bobo_: it searches up the path looking for project.clj files; if the associated project has a jvm it uses that, otherwise it starts a new one

16:26 (if it doesn't find one it uses ~/.cake)

16:26 tomoj: what if the jvm from the first command in the one terminal hasn't finished starting up yet?

16:26 bobo_: it was the same project.clj in all of them

16:28 LauJensen: tomoj: Aren't you the guy who owes me a screencast?

16:28 tomoj: LauJensen: yes

16:28 LauJensen: [======== ] 80% ?

16:28 tomoj: LauJensen: like I said, don't hold your breath

16:28 amalloy: bobo_: i just tested it by opening two ssh sessions to my clojure machine and starting cake repl in the same directory from each of them; it didn't start a new vm the second time?

16:28 tomoj: I haven't quite achieved enough paredit mojo to do the screencast

16:29 LauJensen: k

16:29 tomoj: one of these days soon I will sit down and transcribe all of my paredit knowledge so I can figure out how to make the screencast

16:29 bobo_: i notices railscasts the other day, 233 screencasts on rails. someone should make that for clojure =)

16:29 amalloy: what is tomoj supposed to be screencasting for us?

16:29 bobo_: amalloy: the different terminal thing was a question, it has just happend once, and i have no clue what i did.

16:30 LauJensen: amalloy: He's the guy who'll convince me that paredit isn't training wheels for Emacs kids

16:30 amalloy: LauJensen: well...i like paredit...but i'm an emacs kid, so not a great argument there

16:30 LauJensen: true

16:33 amalloy: But in all honesty, there are veterans who use it as well

16:33 amalloy: yep, i know. otherwise i'd try to learn not to use it

16:44 tomoj: LauJensen: what was your issue again? nice while writing, painful while going back and refactoring/editing code?

16:44 LauJensen: yep

16:48 amalloy: i've actually found it really useful for editing. eg just the simple M-s and C-( for wrapping and unwrapping sexps save me a bunch of paren-hunting

16:49 bobo_: you simple have to make one screencast each to show your points :-)

16:49 LauJensen: Odd, I never go paren-hunting

16:50 tomoj: LauJensen: sorry, what resolution again do you recommend?

16:50 I will write it down this time

16:51 LauJensen: tomoj: np. I think I told you the last time that I usually go for 800x600, but I dont think its optimal. Camtasia and iMovie go for something like 1180x10xx ? Im not sure

16:51 tomoj: I think Vimeo has an entire page on formats you can read through

16:52 ninjudd: tomoj: if the jvm hasn't opened the port yet, it kills it

16:52 tomoj: ah

16:58 LauJensen: Does anybody here have some experience with having Tomcat serve static files ?

17:14 jjido: ,(flatten {:a 33 :b 55 :c 11})

17:14 clojurebot: ()

17:16 LauJensen: ,(sequential? {:a 33 :b 55 :c 11})

17:16 clojurebot: false

17:21 jjido: ,(into [] {:a 33 :b 55 :c 11})

17:21 clojurebot: [[:a 33] [:b 55] [:c 11]]

17:21 jjido: ,(flatten (into [] {:a 33 :b 55 :c 11}))

17:21 clojurebot: (:a 33 :b 55 :c 11)

17:21 jjido: wow :)

17:22 ,(flatten (into nil {:a 33 :b 55 :c 11}))

17:22 clojurebot: (:c 11 :b 55 :a 33)

17:23 jjido: ,(apply ident {:a 33 :b 55 :c 11})

17:23 clojurebot: java.lang.Exception: Unable to resolve symbol: ident in this context

17:23 jjido: ,(apply identity {:a 33 :b 55 :c 11})

17:23 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (3) passed to: core$identity

17:24 jjido: ,(apply concat {:a 33 :b 55 :c 11})

17:24 clojurebot: (:a 33 :b 55 :c 11)

17:27 jjido: I am not there yet... I used (fn [a & {:as amap}] ...) and I want to call it having a map in hand. I don't like doing (apply myfunction a (apply concat mymap))

17:43 scottj: don't quite follow, maybe replace {:as amap} with just amap

17:44 tomoj: jjido: that's the problem with [& {:as amap}]

17:44 why not just use [a amap] ?

17:45 jjido: tomoj: the interface of the function is nicer with &{:as amap}

17:46 I could change it to & alist

17:46 Chousuke: or you could write a kwapply function

17:47 that works like apply but takes a map and expands it into keyword args

17:51 Guest97534: I have a question, is there a way to get a sequence of visited terminals, while walking through a form? clojure.walk seems to ONLY do find/replace ops... (basically, I want to count the occurances of a symbol in certain forms)

17:51 hiredman: have a look at clojure.zip

17:52 or even tree-seq

17:53 Guest97534: Is there a way to make a zipper from a form given to a macro?

17:55 These seem geared towards node functions... I'm not sure how they would work in a macro context

18:00 OK: thanks for the tips, it doesn't seem that hard to use them in a macro-context like so : (tree-seq list? identity '(+ (3 4) 3))

18:01 That gives a traversal of the form, I believe.

18:43 jjido: Chousuke: do I need to test it receives the right kind of data?

18:43 Chousuke: (defn kwapply [function & args] (apply function (apply concat (butlast args) (last args))))

18:44 Chousuke: why are you doing it like that?

18:44 jjido: Chousuke: I felt clever doing it that way ;) What is a good way of doing it?

18:47 amalloy: jjido: it sounds like i joined in the middle of an interesting discussion. what's the "wrong" way?

18:48 jjido: amalloy: (defn kwapply [function & args] (apply function (apply concat (butlast args) (last args))))

18:49 amalloy: that is like apply, but it takes a key-value map and expands it into :key value...

18:51 Chousuke: jjido: I was just thinking of a simplle (kwapply f map) but I suppose that works too.

18:52 except for infinite arg sequences :P

18:52 jjido: Chousuke: would be pervert to call apply with infinite aruments?

18:52 *g

18:53 Chousuke: apply with infinite arguments is just fine

18:53 as long as the function works with infinite arguments.

18:54 ossareh: very happy to be a clojure hacker today :) (having just returned from the realm of javascript)

18:54 Chousuke: ,(take 10 (apply concat (partition 2 (range))))

18:54 clojurebot: (0 1 2 3 4 5 6 7 8 9)

18:55 jjido: Chousuke: you didn't

18:55 amalloy: jjido: i guess i see what kwapply does, but why do you want to do it? there aren't really that many functions that want a list of k/v pairs, are there?

18:55 Chousuke: hmm

18:56 jjido: amalloy: I wrote one. It initialises a record by copying the bindings provided in the argument list.

18:58 Chousuke: ,(take 2 (apply apply concat (partition 2 (range))))

18:58 clojurebot: java.lang.StackOverflowError

18:58 jjido: Chousuke: looks like you did it :)

18:59 amalloy: jjido: i made a macro for doing something similar that you might find interesting: http://gist.github.com/608075

19:00 jjido: amalloy: I am not good with macros (ie., looking at your code makes my head ache)

19:03 amalloy: jjido: updated the gist with an example usage

19:04 jjido: amalloy: yeah that is similar to my code then

19:05 amalloy: well, but mine takes a map instead of & kvs, so you wouldn't need kwapply

19:06 (also the performance is way worse than calling the actual constructor, so don't do this in anything where speed matters)

19:09 jjido: amalloy: is it an advantage that it takes a map? I like having one set of { }s less

19:09 amalloy: I copied my code here: http://gist.github.com/608085

19:12 amalloy: jjido: but you have just as many {}s, don't you? (kwapply myfunc arg1 arg2 {:opt1 10 :opt2 "test"})

19:13 jjido: amalloy: no I do not use kwapply for that, I use it in the function that passes key-values to another function

20:11 ,(~:count)

20:11 clojurebot: java.lang.IllegalStateException: Var clojure.core/unquote is unbound.

20:46 amalloy: ,`(~:count)

20:46 clojurebot: (:count)

20:46 amalloy: jjido: ^^

20:47 jjido: amalloy: I was looking at the wrong thing :P I wanted

20:47 ,(keyword 'count)

20:47 clojurebot: :count

20:48 jjido: is it possible to get rid of the ' ? Are function arguments always evaluated?

20:49 amalloy: function arguments are always evaluated. if you need them to not get evaluated, that's what macros are for

20:49 jjido: amalloy: ok I need a macro then

20:49 ataggart: alternately you can use delay

20:50 though probably not what you want

20:50 jjido: Would be nice if I could write (call* y head) instead of (call* y 'head)

20:51 amalloy: jjido: i can't def things in #irc, but try: (defmacro kw [name] `(keyword '~name)) (kw count)

20:52 it delays the evaluation of count until it's had a chance to put a ' in front of it

20:54 jjido: amalloy: and if I want one of the args of my macro to be evaluated? (because it is used twice in the macro body)

20:55 do I do a (let) before ` ?

20:55 amalloy: (defmacro [eval-me] `(let [val# ~eval-me] [val# val#]))

20:55 you can do a let before the `, but it won't be able to evaluate eval-me - that's happening at compile time, and it won't have a value yet

20:56 jjido: oh I see

20:56 amalloy: eg, eval-me will be (+ 1 2) instead of 3

20:58 jjido: amalloy: are there special rules for varargs macros?

20:59 amalloy: nope. macros are just like functions, except that their arguments aren't evaluated, and their return value is expanded inline

20:59 jjido: ie. can the additional arguments be inserted without apply?

21:00 amalloy: you mean like: (defmacro make-list [& elts] `[~@elts])? i think that works

21:01 yeah, it does

21:03 jjido: cool :)

21:03 amalloy: well. this isn't a cure-all to avoid apply, though

21:04 jjido: amalloy: I was writing a macro anyway :)

21:04 amalloy: eg, this won't work: (let [elts [1 2 3 4]] (make-list elts))

21:04 jjido: (defmacro call* [obj, getter & args] `(let [var# ~obj] (((keyword '~getter) (class* var#)) var# ~@args)))

21:04 amalloy: doesn't it create a single-element list?

21:05 amalloy: yes, it creates the list [[1 2 3 4]]

21:05 jjido: then it works ;)

21:05 amalloy: heh, okay

21:06 jjido: hm, neat

21:07 KirinDave: In Let Over Lambda they detail some very cool macro hacks to do eval-once macros.

21:07 coldhead: also that book is abbreviated LOL

21:07 it even says LOL on the cover

21:08 KirinDave: Yup.

21:08 amalloy: KirinDave: but we barely need those in clojure. the gensyms are forced on us and un-painful, so it's only the initial let that could be made easier

21:09 KirinDave: amalloy: The single-evaluation part would be smart to port in.

21:09 The other stuff is basically to give you what clojure already has with sym#.

21:10 amalloy: KirinDave: but you'd have to leave the current feature present; it's hard to generalize what kind of eval-once functionality people want

21:12 KirinDave: It's not hard at all.

21:12 Maybe I'll put it in the book.

21:12 It's a very useful macro.

21:14 amalloy: i haven't read LOL, though i saw an eval-once macro in PCL or some similar book online, and it's not clear to me what the feature would even look like in clojure. what do you envision the ideal use-case being?

21:14 KirinDave: Facilitating single-evaluation.

21:16 It's very useful in macros. Most of the time in clojure people sidestep the issue by using (fn ...), in my experience.

21:16 Since clojure is so functional, you can sneak around.

21:17 amalloy: KirinDave: i mean, a concrete example. i'm a dev who wants to write a macro with your eval-once feature, what should my code look like?

21:17 KirinDave: It'd just be like sym#

21:17 You'd say, maybe sym@

21:18 Which means that the sym@ params passed to the macro will be (let [sym@ form] ...) before further macro processing.

21:19 As for why you'd want to use it...

21:19 amalloy: KirinDave: i see. you imagine them being evaluated once, immediately before being used?

21:19 KirinDave: Yes.

21:20 Let's say one of your macros takes a function param and splices that in.

21:20 jjido: KirinDave: why not allow sym# in the arg list?

21:20 KirinDave: If you dont' single-eval it, the function gets redefined.

21:20 jjido: sym@

21:20 jjido: Becuase that's the only place it makes sense and that the macro can act.

21:20 amalloy: i was trying to sort out the order in which they're evaluated if there are more than one of them, but i guess if you don't let until they're used it's likely to be right most of the time

21:20 KirinDave: You only care about collapsing evaluation for injected forms.

21:21 Because those are the only ones where you don't know what the implications of multiple evaluation are.

21:21 amalloy: Convention is to go left-to-right on the args list.

21:21 Let over lambda is an insanely good book, even if you want to just do clojure.

21:22 A lot of chapters you can and will just skip

21:22 But a lot of it is printed gold.

21:22 amalloy: KirinDave: damn it, don't make me order books while there are already some in the mail

21:23 KirinDave: LOL is a better book even that the MOP book.

21:26 jjido: like that? (defmacro example [x y@] (if (> ~y 0.5) (+ ~x (* 2.0 ~y)) (+ ~x 1.0)))

21:27 I like better: (defmacro example [x y#] (if (> y# 0.5) (+ ~x (* 2.0 y#)) (+ ~x 1.0)))

21:27 amalloy: seriously though: (cond false param@, :else param@), vs (cond false param@, false param@). how can your gensym function be smart enough to get both of these right in the case where param has side effects?

21:28 in the first case it needs to wrap the cond with a let; in the second it needs to wrap each param with a let

21:29 jjido: amalloy: if you use that, you should expect a single let shouldn't you?

21:30 amalloy: damn it, i guess i'm wrong there too; in the first case it can still just wrap each param. but there are places where you have to wrap a containing form, and in the second example you need to wrap each param@ to prevent them being evaluated if the conds fail

21:31 jjido: it can get pretty hairy

21:31 KirinDave: amalloy: The thing@ semantics are "it will be evaluated once and the result used everywhere"

21:31 That's important with things that might be expensive or need identity.

21:32 jjido: KirinDave: like memoization?

21:32 KirinDave: Um, sure. But at a lexical level

21:32 amalloy: KirinDave: sure, i understand. are you saying that it will be evaluated regardless of what's in the macro body? i thought the idea was to not eval them unless their code is executed, in which case eval them exactly once

21:32 KirinDave: No, @ means you'd always evaluate.

21:32 Code tracing is too much work.

21:32 But clojure has laziness and promises, so it's no big deal

21:33 Make the form a future and bam

21:33 hiredman: you'd want delays

21:33 future's are always run

21:33 on another thread

21:33 amalloy: i see. that's not too hard then, and i guess saves some code

21:34 hiredman: if you bind the name to a delay then replace the name in the code with a force of the delay it will only be eval'ed once

21:34 KirinDave: Sure.

21:34 Heck

21:34 hiredman: KirinDave: are you modeling the webmachine graph via just function calls?

21:35 KirinDave: yes, for now

21:35 Teh stack depth only can hit 25 in the worst case scenario.

21:35 So I think it's okay

21:35 hiredman: have you thought of using some kind of stream processing library like, say, conduit?

21:36 KirinDave: No.

21:36 Would that be valuable?

21:37 hiredman: it would be neat

21:37 KirinDave: Why?

21:37 clojurebot: why not?

21:37 hiredman: it's very graphy

21:38 KirinDave: Wanna see what I have now?

21:38 it'll be open source soon, so I don't mind showing you what's in the pipe.

21:38 hiredman: http://gist.github.com/608171 is an example of what the first column might look like

21:40 I am curious, but I don't know if I am that curious

21:43 jjido: hiredman: is a-comp / pass-through a macro?

21:45 hiredman: no

21:45 they are all functions

21:46 KirinDave: Weird

21:46 You'd think they'd be part of a macro for a compiler.

21:46 That could do things like detect where function boundaries Must be.

21:46 hiredman: why??

21:47 conduit is based on an arrows implementation in clojure that models arrows as maps

21:47 KirinDave: I do't know if I fully understand that arrows thing.

21:48 hiredman: *shrug* I don't claim to either but it hasn't stoppped me from writing a lot of conduit code

21:48 anonymouse89: I'm trying to find an equivalent clojure statement to the Java: Foo[] foos = bar.toArray(new Foo[bar.size()]);

21:48 KirinDave: So what's the value add of conduit over what I am doing, now that you've seen it?

21:48 anonymouse89: but do not know how to do the "new Foo[bar.size()]" portion

21:49 KirinDave: ,(doc make-array)

21:49 clojurebot: "([type len] [type dim & more-dims]); Creates and returns an array of instances of the specified class of the specified dimension(s). Note that a class object is required. Class objects can be obtained by using their imported or fully-qualified name. Class objects for the primitive types can be obtained using, e.g., Integer/TYPE."

21:49 hiredman: KirinDave: you don't need to write big macros

21:50 KirinDave: hiredman: Is my macro hard to read?

21:50 anonymouse89: sorry for the silly question

21:50 hiredman: I dunno, it just seems a lot more complicated

21:51 I'm not familiar with webmachine so I could be missing something

21:51 KirinDave: hiredman: Please elaborate. I'm a common lisp guy, so I tend to approach things syntactically.

21:51 amalloy: anonymouse89: is there a reason you need to use java arrays? if so KirinDave's answer is definitely right, but if you can stick with clojure data types you'll probably be happier

21:51 hiredman: http://gist.github.com/608183 you can do nodes like this

21:52 KirinDave: Well the rub is that some of the states will not be simple test nodes.

21:52 Some of them actually have logic.

21:52 Which is where has-body? comes in.

21:52 clojurebot: group? is http://groups.google.com/group/clojure

21:54 hiredman: the graph is transitions based on true/false are you not implementing the graph?

21:54 KirinDave: Up to where I have the graph implemented it's simple true-false.

21:54 Some of the deeper nodes have more to do.

21:54 hiredman: I am looking at the image of the graph

21:54 KirinDave: yeah

21:54 hiredman: everything is true/false red/green

21:54 KirinDave: So an example is the node I am up to.


21:54 That's gotta prepare a response.

21:55 And there are a few ways I could do that.

21:56 hiredman: (a-if options? two-oh-oh-ok c3), would take an input, apply the options? predicate, and if the result is true, pass the input on to two-oh-oh-ok and if false to c3

21:57 KirinDave: How does that library solve the forwards invocation problem?

21:57 Does it just not?

21:57 hiredman: forwards invocation?

21:57 KirinDave: Right now I'm doing (ns-resolve ...)

21:57 So that you don't have to define the graph in reverse order.

21:58 hiredman: you can solve it the same way you do with functions

21:58 using declare

21:58 KirinDave: I hope that, at least, is something people do with a macro.

21:58 hiredman: but I would just do it in reverse

21:59 since that seems more natural

21:59 KirinDave: To go from finish to start?

21:59 hiredman: no

21:59 to build up

21:59 from basic nodes to nodes that depend on those nodes

22:02 KirinDave: I may keep it as functions permanently, either way

22:02 because I can just annotate the functions with metadata.

22:02 hiredman: *shrug*

22:02 KirinDave: But thanks for mentioning conduit. It's interesting.

22:03 hiredman: sure

22:05 there isn't an http transport for conduit atm but I know jim is interested in getting one and I have been thinking about what that might end up looking like

22:06 anonymouse89: amalloy: yeah, unfortunately I'm having to deal with Java libraries directly

22:18 KirinDave: hiredman: Are you involved with the conduit project?

22:24 hiredman: KirinDave: I work with jim at sonian and did a conduit transport for hornetq

22:25 KirinDave: Ah.

22:25 I didn't know you were also @ sonian.

22:25 hiredman: did? doing? as far as I know it's working but I have yet to use the hornetq transport anywhere

22:25 KirinDave: I was interviewing with them.

22:26 hiredman: right I think tim mentioned

Logging service provided by n01se.net