#clojure log - Sep 13 2010

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

0:00 sproust: See what happens is that I'm using this: (if (seq coll) ... ) Doesn't look like the rest, doesn't look like a predicate. It would be better IMHO write (if (not-empty? coll) ...

0:01 (I know, I can cook my own... but then it's not idiomatic clojure anymore, as per the docs.)

0:02 wwmorgan: well, it's not just seq that you would use in that position, but any function that could potentially return nil

0:02 rather than false, for example

0:03 sproust: ,(map boolean [nil false])

0:03 clojurebot: (false false)

0:06 anonymouse89: sproust: is (if (not (empty? coll))... not idiomatic?

0:06 sproust: wwmorgan: not sure I'm being clear-- I understand I could put any other function there; what I take issue with is the fact that the idiomatic/recommended way to check that a collection isn't empty (a very common task) isn't a predicate (e.g. "something?").

0:06 ,(doc empty?)

0:06 clojurebot: "([coll]); Returns true if coll has no items - same as (not (seq coll)). Please use the idiom (seq x) rather than (not (empty? x))"

0:07 anonymouse89: ah

0:07 sproust: Yup.

0:07 Zhivago: Apparantly someone thinks that the empty sequence is not a sequence.

0:09 anonymouse89: next time I'll scroll back some

0:09 wwmorgan: sproust: I think I get it. If it makes you feel any better, the macros and and or are in the same boat

0:09 sproust: Zhivago: so in your mind's eye you're thinking: "I have to get the ISeq using (seq) because the sequence might be empty (and that's a boolean true) but I know that the ISeq will eval to false if it's empty." ?

0:09 clojurebot: @ splices in a seq and foo# is a symbol, not a seq

0:11 wwmorgan: sproust: aha! I got a good example, I think

0:11 ,(if (filter #(< 0 %) (range)) 0 1)

0:11 clojurebot: 0

0:12 sproust: ,(range)

0:12 clojurebot: Execution Timed Out

0:13 wwmorgan: (range) is the same thing as (iterate inc 0)

0:13 sproust: wwmorgan: great example.

0:14 wwmorgan: a major use case for seq is forcing a lazy collection. You use seq to ask, is there a collection here, or not?

0:17 sproust: I see. I understand your way of thinking.

0:19 wwmorgan: fwiw, I used (not (empty? ...)) for a while before changing my style

0:21 sproust: Well, I still think it's slightly twisted. But I guess (defn not-empty? [coll] (seq coll)) will put me to rest.

0:22 I'll probably give in in a week ;-)

0:22 wwmorgan: (def non-empty? seq) will do it too ;-)

0:22 Zhivago: Wouldn't empty? and then (unless (empty? ...) ...) make more sense?

0:24 scottj: when-not

0:25 wwmorgan: Zhivago: sure. But the idiomatic way would be (when (seq c) ...), for the couple reasons discussed above

0:25 sproust: Zhivago: unless doesn't provide an else form

0:25 s/unless/when-not/

0:25 sexpbot: <sproust> Zhivago: when-not doesn't provide an else form

0:25 scottj: if-not

0:26 johnmn3: hi

0:26 sproust: Allright, you win.

0:26 (if-not (empty? coll) ... )

0:26 johnmn3: trying to do a lein deps on a git clone of clojars-web. Failing to get: 1.1.0-alpha-SNAPSHOT

0:26 sproust: I'll buy that. [deleting not-empty?]

0:26 johnmn3: I tried changing the name to 1.1.0 but it is still looking for the old name

0:29 scottj: johnmn3: weird. does lein clean help? you saved project.clj right? :) just "1.1.0" right?

0:29 johnmn3: yea, trying again with contrib as just 1.0 too

0:29 scottj: maybe checkout a fork

0:30 you looking to improve clojars-web or deploy a local one?

0:31 johnmn3: set the website up locally, so I can mess around with it, maybe help out if I can figure it out.

0:31 what should clojure-contrib be? was: [org.clojure/clojure-contrib "1.0-SNAPSHOT"]

0:32 I just tried: [org.clojure/clojure-contrib "1.0"]

0:32 with no luck

0:33 do I need to clean/purge .m2 out as well somehow?

0:33 scottj: http://github.com/kotarak/clojars-web/blob/master/project.clj

0:35 johnmn3: scottj, thanks, will try that

0:37 worked

0:38 now, I need to get the clojure-web/data too?

0:40 scottj: no clue, never setup clojars

1:06 johnmn3: hmm. The kotarak readme says to run: java -cp 'src:classes:lib/*' -i src/clojars/core.clj -e '(clojars.core/main)'

1:06 but java says there's no such -i option

1:06 chouser: hm. trying inserting clojure.main right before the -i

1:07 johnmn3: ah, k

1:08 wow.. I have clojars.org running locally

1:08 chouser: nifty!

1:10 johnmn3: the repo isn't browsable or searchable yet, but registering just worked.

1:41 sandGorgon: why do I need to use a "alter" keyword in a "dosync". I can do changes by using deref/"@". Is there something I'm missing ?

1:42 wwmorgan: sandGorgon: how can you make changes using deref?

1:43 johnmn3: when you deref, you are making a copy of that value.

1:43 sandGorgon: wwmorgan, lets say (def some-num (ref #{1 2 3})) . Then (dosync (alter @some-num conj 4)) or (dosync (conj @some-num 4)) is the same isnt it ?

1:43 johnmn3, so alter doesnt ? I thought all data-structures were immutable ?

1:44 wwmorgan: sandGorgon: not the same thing. After executing the first form, some-num will be chaned. After executing the second, it will not

1:44 johnmn3: few things.. in your example, you don't need to use the @

1:44 (dosync (alter some-num conj 4))

1:45 wwmorgan: oh yes, that too. The first form won't do what you want

1:45 johnmn3: (conj @some-num 4)

1:45 alter has specific semantics that only make sense relative to a dosync (inside a transaction)

1:45 transactions are a certain way to do things.

1:46 allowing syntax like (dosync (conj some-num 4)) would muddy the meaning of (conj some-num 4)

1:47 because a different kind of thing is happening with (dosync (alter some-num conj 4))

1:49 SandGorgon: johnmn3, I got disconnected - would you please repeat ur message ? my last question was johnmn3, so alter doesnt ? I thought all data-structures were immutable ?

1:49 johnmn3: few things.. in your example, you don't need to use the @

1:49 (dosync (alter some-num conj 4))

1:49 (conj @some-num 4)

1:49 alter has specific semantics that only make sense relative to a dosync (inside a transaction)

1:49 transactions are a certain way to do things.

1:49 SandGorgon: true true.. (dosync (alter @some-num conj 4)) should have been (dosync (alter some-num conj 4))

1:50 johnmn3: allowing syntax like (dosync (conj some-num 4)) would muddy the meaning of (conj some-num 4)

1:50 because a different kind of thing is happening with (dosync (alter some-num conj 4))

1:51 they are different forms that do different things. one operates on the identity while the other operates on the value (returning a new value)

1:52 the first returns a new value, but redirects the identity to the new value, sotospeak

1:53 SandGorgon: johnmn3, ahh.. that is something that makes sense

1:53 johnmn3: it's confusing at first

1:54 a deref or @ pulls the current value out

1:55 so you could do something like, (dosync (alter some-num conj (inc @some-num)))

1:55 SandGorgon: right.. got that - I sort of lost the fact that identity needs to be redirected

3:00 amalloy: didn't rich post to the group about new stack trace functionality? i'm sure i saw it, but i'm totally baffled in that i can't find it anywhere

3:06 chouser: http://groups.google.com/group/clojure/browse_thread/thread/fd6cd491862bf9e5

3:06 LauJensen: Good morning all

3:06 chouser?!

3:06 chouser: amalloy: google group's search is stunningly bad

3:06 LauJensen: yeah, I really shouldn't be awake.

3:06 LauJensen: chouser: Those finger trees got you up at night now?

3:09 chouser: nah, just a late night snack.

3:09 and that's consumed now, so off to bed with me.

3:09 have a pleasant whatever it is!

3:11 LauJensen: Right back atcha

3:38 Anybody here from Austria?

3:57 amalloy: no, but one of my coworkers is from australia, so...let me know if you get desperate

4:03 LauJensen: thanks, I will

4:08 AWizzArd: Isn't Australia on the other side of the world?

4:08 From Austria I mean.

4:08 amalloy: spelled similarly, though. best i could do

4:12 zoldar: I'm trying to alter a session but when executing "(alter session assoc :name val)" I get "clojure.lang.PersistentArrayMap cannot be cast to clojure.lang.Ref" which probably refers to session map. I have extracted session inside defroutes using map destructuring. What am I doing wrong?

4:14 LauJensen: amalloy: I appreciate the effort :)

4:14 zoldar: just call assoc session :name val, alter is for dosyncs/refs

4:15 Make sure you associate the modified data to the return of the handler

4:15 (assoc (response "Hi there") :name "Frank")

4:30 zoldar: LauJensen, sorry to bother you again but I'm not sure how to go about this when inside defroutes I'm delegating destructured data to separate functions - here's my (failed) attempt which I'm struggling with: https://bitbucket.org/zoldar/clj-smbbrowser/src/tip/src/clj-smbbrowser/core.clj

4:31 LauJensen: Its been a while since I've played with Compojure, but try (defroutes r (GET "/" [] (assoc (response "OK") :session {:username "Frank"}))) which should put franks username in the session. Note however, that if a single handler in your routes returns nil, the session will be deleted

4:32 zoldar: ok I will play around with it, thanks for pointers

4:34 LauJensen: np - though just looking through your code, I think if this is going to turn into anything larger than what I see in that file, you would want to try Moustache/Enlive

4:36 zoldar: well I wanted to try going the no-template-engine route ;) I'll see how it goes. It's my first clojure code longer than a snippet

4:37 LauJensen: Alright - Why did you want that?

4:39 zoldar: well with that I don't have to switch between various languages (not so often at least). Besides in that case it's only me working on the code

4:39 LauJensen: You mean switch between clojure and html ?

4:41 zoldar: well, yes - I know it sounds stupid, but I hope for better flexibility with moving pieces around when using clojure directly for structuring documents

4:41 at least when I'll get more fluent with it

4:43 LauJensen: I don't understand how mixing code and representation will give you more flexibility than a complete separation, can you elborate?

4:45 hamza: IMHO it is much nicer to work with hiccup then html, you can still keep representation away from code.

4:46 zoldar: LauJensen, flexibility in terms of tools available in clojure itself when comparing to limited range of tools provided by template engine

4:46 LauJensen: zoldar: The template engine has its own tools, as well as all of the tools of Clojure

4:48 zoldar: LauJensen, well I won't argue because I'm too inexprienced at that stage, maybe you are right in the longer run. For now I ok with hiccup - using it also helps me to leverage my knowledge of the language

4:48 LauJensen: ok

5:37 fliebel: morning

5:39 LauJensen: morning

5:41 mbuf: are there any recommendations/tutorials for using clojure as backend, and Rails as a front-end?

5:42 LauJensen: mbuf: I suppose what you're looking for is a tutorial on using Clojure as a backend which communites via REST or some such interface, with just about anything?

5:44 mbuf: LauJensen: yes

5:44 msappler: Hi is there some very good "stop using java - start using clojure" article or essay around?

5:44 So I do not have to write one myself

5:45 LauJensen: msappler: cemerick wrote one called "Java is dead, you'll love it", I forgot the content though :(

5:46 cemerick: msappler: http://cemerick.com/2009/10/01/java-is-dead-but-youll-learn-to-love-it/

5:46 LauJensen: mbuf: here's one take: http://mmcgrana.github.com/2010/08/clojure-rest-api.html

5:47 cemerick: morning :)

5:47 mbuf: LauJensen: thanks

5:47 cemerick: LauJensen: morning :-)

5:47 LauJensen: cemerick: Did you see that tweet I sent your way ?

5:47 cemerick: I hadn't looked at twitter yet.

5:48 LauJensen: Thanks :-)

5:48 LauJensen: ok, just wondering if you see such tweets now that we're not following each other. I've had some problems with DMs on that note

5:50 cemerick: LauJensen: did we ever follow each other? I thought *I* was selective in who I followed, but you take it to the next level!

5:50 LauJensen: haha - I don't know if you've followed me and unless you tweet less than once a week, I don't follow you

5:51 msappler: Hm That essay was not really what I meant ... I meant some kind of essay that can be sent to java developers that shows them the advantages they can get if they start using clojure... more like a comparison.

5:51 cemerick: I come and go in waves. ;-)

5:51 I wish twitter profile pages showed stats: tweets/day over the last week, month, three months, etc.

5:53 LauJensen: cemerick: Wow, you actually did a fund raiser for Raynes ? Good move

5:53 cemerick: yup, it was very successful

5:54 LauJensen: Thats heart warming

5:54 notsonerdysunny: how to find the list of all vars in a given namespace in clojure

5:54 LauJensen: And it couldn't have happend to a nicer guy :)

5:54 hamza: ,(doc ns-publics)

5:54 clojurebot: "([ns]); Returns a map of the public intern mappings for the namespace."

5:55 hamza: notsonerdysunny: ns-publics

5:56 notsonerdysunny: hamza: thanks

5:56 hamza: notsonerdysunny: np

6:00 notsonerdysunny: just out of curiosity .. why map? why not just a set? what extra-info is the value part of the map giving us? wouldn't just the keys suffice?

6:03 hamza: value part is a pointer to the function

6:03 ,(((ns-publics 'clojure.core) 'sorted-map))

6:03 clojurebot: {}

6:17 notsonerdysunny: what is it returning when the symbol is not a function.. for instance .. what is s which has been defined using (def s 10)

6:17 when I do a (class <value>) it just says it is a var..

6:18 I was expecting it would say it is an integer

6:18 mrBliss: ,(def s 10)

6:18 clojurebot: DENIED

6:19 mrBliss: When I do it in my REPL, (class s) returns java.lang.Integer

6:19 notsonerdysunny: ,(def s 10)

6:19 clojurebot: notsonerdysunny: Excuse me?

6:19 notsonerdysunny: mrBliss: you are right .. but I am refering to the value part of the map returned by (ns-publics <namespace>)

6:20 corresponding to the key "symbol s"

6:20 <namespace> would be the one I executed (def s 10)

6:21 mrBliss: in the map you get #'user/s instead of user/s, #' is a sort of var quote

6:21 notsonerdysunny: yes .. how would I find out what is the type of the object contained in #'user/s ?

6:22 mind you I want to do it using the value part of the map returned...

6:23 mrBliss: try var-get

6:23 notsonerdysunny: gotcha .. I would add a "deref" or @

6:24 mrBliss: is the same as var-get in this context

6:26 notsonerdysunny: yea

6:42 the gen-class ed classes and definterface d classes don't seem to be visible when I do (ns-publics <namespace> ) .. is that expected?

6:47 for instance for the file http://gist.github.com/577118

6:51 fbru02: guys stupid question time , what's the meaning of # in clojure? e.g. (defmacro dbg[x] `(let [x# ~x] (println '~x "=" x#) x#))

6:51 ?

6:51 mrBliss: it generates a unique symbol

6:51 ,x#

6:51 clojurebot: java.lang.Exception: Unable to resolve symbol: x# in this context

6:52 mrBliss: so it doesn't conflict with existing symbols

6:52 fbru02: mrBliss: thanks, so it doesn't collide with symbol named x for example??

6:53 mrBliss: exactly

6:53 arbscht: ,`,x#

6:53 clojurebot: x__5439__auto__

6:53 fbru02: cool

6:54 mrBliss: every x# in that macro will be the same unique symbol

6:54 ,(doc gensym)

6:54 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__'."

6:56 raek: notsonerdysunny: yes, I think so. the classes are not vars of a namespace

6:57 I don't even think that the package of the generated class has to match the one of the namespace containing the gen-class

7:05 notsonerdysunny: raek: you are right

7:05 but I have explicitly made sure it does match

7:06 so is there a way to get all the classes and interfaces of a package?

7:08 ->x#

7:08 sexpbot: java.lang.Exception: Unable to resolve symbol: x# in this context

7:08 notsonerdysunny: ->`,x#

7:08 sexpbot: => x__11431__auto__

7:09 notsonerdysunny: ->`~x#

7:09 sexpbot: java.lang.Exception: Unable to resolve symbol: x# in this context

7:09 notsonerdysunny: ->`->x#

7:09 sexpbot: => ->x__11444__auto__

7:09 notsonerdysunny: `->x#

7:22 is there a function to list all the classes in a given package?

8:10 naeu: How do I refer to an agent's current value from within itself?

8:10 I'm assuming that dereferencing an agent within itself is problematic

8:15 is there something like 'self' that you can reference in a function being executed by an agent?

8:15 cemerick: naeu: The current value of the agent is provided to the function you send or send-off to the agent.

8:16 naeu: cemerick: sorry, I'm being confusing - can you also get the actual agent itself?

8:16 i.e. so you can schedule another send?

8:17 cemerick: naeu: see *agent*

8:17 naeu: cemerick: perfect, thanks :-)

8:36 opqdonut: how do I solve "Can't embed object in code" ?

8:36 when compiling

8:41 Bahman: Hi all!

8:42 LauJensen: hi Bahman

8:42 opqdonut: Find the line thats causing it

8:42 opqdonut: I know the object that's causing it

8:42 Bahman: LauJensen: Yo.

8:42 opqdonut: can I somehow tell clojure how to read it?

8:45 LauJensen: opqdonut: I have no idea without seeing the code. I vaguely remember having had that problem myself, and solved it, but the details are lost

8:46 opqdonut: I understand what's happening here: clojure wants to be able to store constants into the generated class

8:46 for some reason it uses print-dup to do this

8:46 understandably, it doesn't like my custom toString in one class

8:49 LauJensen: ah ok, so implement print-dup for your class ?

8:49 opqdonut: ok, where is this documented?

8:50 what signature should the method have?

8:51 hmm, public void printDup(Writer w) it seems

9:04 oh, hmm, yes

9:04 it's defmethod clojure.core/print-dup I should use

9:04 the definition actually was there, it just wasn't getting used

9:15 fliebel: Is there a simple way so that my app can get command line arguments both when compiled and when run as clj file?

9:16 *interpreted

9:20 For interpreted there is *command-line-args*, but for compilation I think I have to generate a class with a main function, right?

9:20 raek: yes

9:21 command line args to a repl end up in *command-line-args*, and those to a class end up in the parameter of main

9:22 fliebel: :( So the best way would be to do (apply main *command-line-args*) for interpreted code?

9:22 raek: as of now, I think so yes... (please correct me if i'm wrong, #clojure)

9:25 LauJensen: I think thats right

9:51 fliebel: :( Cake doesn't like me… I'm trying to set up a custom task, but it gives me nothing but errors.

9:51 LauJensen: fliebel: Can you gist it?

9:52 fliebel: LauJensen: I have nothing to show, it's just that I don't know how to do it properly. It seems deftask is defined in cake.core, but I can't use or require it.

9:52 arkh: can anyone tell me what I'm missing with re-matches ?

9:52 ,(let [s "asdf"] (if (re-matches #"a" s) '(:yes) '(:no)))

9:52 clojurebot: (:no)

9:53 LauJensen: fliebel: What do you want your task to do ?

9:53 fliebel: LauJensen: Just to print hello for now… How is that relevant?

9:54 LauJensen: fliebel: Because you initialize your tasks differently, depending on whether or not they need full access to your projects vars, or just run on the outside

9:54 fliebel: They need to do stuff with the rest of the project.

9:54 Raynes: cemerick: I'll throw that info your way as soon as my eyes open to full width. :)

9:54 fliebel: LauJensen: It's for the static site generator, I want to use cake to do the compiling and other commands.

9:55 LauJensen: In your project.clj, try adding (deftask hello [] (println "hello")) and run 'cake hello' from cli

9:55 Thats the most basic use case. If that works, try (deftask hello (bake (:use something.in.your.project) [] (println "hello")))

9:56 Which will then have access to the full project classpath

9:56 Raynes: Congrats on your trip to Clojure Conf - I was excited to read about the process!

9:56 fliebel: LauJensen: Why in project.clj? They told me to put it in tasks.clj

9:56 clojurebot: LauJensen is some dane

9:56 Raynes: Thanks. :>

9:57 raek: arkh: (let [s "asdf"] (if-let [match (re-find #"a" s)] `(:yes ~match) '(:no)))

9:57 LauJensen: fliebel: just trying to keep it simple, now do as I say or prepare for the consequences

9:57 fliebel: okay

9:58 LauJensen: arkh: I think you're looking for re-find

9:58 ,(let [s "asdf"] (re-find #"a" s))

9:58 clojurebot: "a"

9:58 LauJensen: (fliebel I was just kidding :P)

9:58 fliebel: LauJensen: Step 1 works :)

9:58 LauJensen: okay great, then Step #2 will probably also work

9:58 arkh: ultimately I'd like to get a seq with re-groups, but I want to test for existence of a match object first

9:58 LauJensen: Then we can also discuss which part of the build you want your task to depend on

9:59 ,(when-let [we-have-matches (re-find #"a" "asdf")] (println "matches: " we-have-matches))

9:59 clojurebot: matches: a

9:59 fliebel: LauJensen: It says something.in.your.project does not exists (also kidding)

9:59 LauJensen: haha

9:59 arkh: raek: thank you - why won't the 'if' at least return true on a match?

10:00 LauJensen: arkh: see example above

10:00 raek: ,(re-matches #"a" "asdf")

10:00 clojurebot: nil

10:00 arkh: oh

10:00 raek: ,(re-matches #"(a)" "asdf")

10:00 clojurebot: nil

10:01 raek: hrm

10:01 re-find and re-seq re the only regex fns I use

10:01 fliebel: LauJensen: Great, also works… Now what? Just keep all tasks in project.clj? *meanwhile looks up bake*

10:01 arkh: LauJensen: thanks - would that work with re-groups ?

10:01 LauJensen: arkh: yea it works with groups

10:02 raek: ,(re-find #"(a)(s)(d)(f)" "asdf")

10:02 clojurebot: ["asdf" "a" "s" "d" "f"]

10:02 LauJensen: fliebel: I keep them in project.clj

10:03 raek: ,(if-let [[_ a s d f] (re-find #"(a)(s)(d)(f)" "asdf")] [a s d f] :no-match)

10:03 clojurebot: ["a" "s" "d" "f"]

10:03 * arkh doesn't like re-matches always returns nil

10:03 raek: it is weird, indeed

10:03 ~re-matches

10:03 clojurebot: I don't understand.

10:03 raek: (source re-matches)

10:04 ~(source re-matches)

10:04 clojurebot: source is http://github.com/hiredman/clojurebot/tree/master

10:04 fliebel: LauJensen: Fine with me, they'll just invoke some function and quit. But what is the bake command for? Is it like ns for tasks?

10:06 LauJensen: ah: http://github.com/ninjudd/cake/blob/master/src/cake/core.clj#L156

10:07 So, Now I only need to figure out deftemplate, and I'll be on my way. Thanks LauJensen!

10:10 LauJensen: np :) Sorry I was afk, a danish mainstream IT media called me and wanted to talk about the release of Clojure 1.2 - Amazing the attention its getting

10:12 boojum: LauJensen: who?

10:12 LauJensen: Version2

10:13 boojum: cool

10:14 fliebel: LauJensen: Cool :)

10:17 arkh: raek: LauJensen: looks like a person should usually stick with re-find and re-seq. They both take a match object, if available, and call re-groups on it. I still think it's confusing given the re- documentation but oh well.

10:17 not so much fyi, more of a "I think I finally get it" ; )

10:21 kjeldahl: Anything similar to perl's Data::Dumper in Clojure? I'm stuck with debugging a clojure module which speaks to a java host which filters all (including stderr) output...

10:22 (it dumps abstract data, including trees, lists etc)

10:24 raek: something like pr?

10:24 ,(pr-str {:a 1, :b 2, :c ["foo" "bar]})

10:24 clojurebot: EOF while reading string

10:24 raek: ,(pr-str {:a 1, :b 2, :c ["foo" "bar"]})

10:24 clojurebot: "{:a 1, :b 2, :c [\"foo\" \"bar\"]}"

10:24 kjeldahl: Excellent, thanks!

10:38 fliebel: LauJensen: My deftask is still not working… I created a lovely macro to make it DRY, but that turns deftask into bake.core/deftask and then complains it can't find it. I might be doing something stupid, but I suspect there is some dirty hackery in Cake to get defmacro in my project.clj

10:44 jweiss: technomancy: http://github.com/technomancy/dotfiles/blob/master/.emacs.old/behave/behave.el I don't suppose there's something like this in clojure? I'm looking at ways to make manually written tests (plain english) and automated tests come together

10:44 LauJensen: fliebel: Im not sure its such a great idea to wrap it in a macro, just use the macros that are already made available

10:46 fliebel: LauJensen: I don't like having the full expanded thing laying around a dozen times: (defmacro dt [hook] `(deftask ~hook (bake (:use utterson.plugin) [] (execute ~(keyword hook)))))

10:49 LauJensen: Which macroes that are already available are you talking about?

10:51 LauJensen: deftask and bake

10:53 fliebel: LauJensen: So that is basically the expanded form of my macro x 5

10:54 LauJensen: Why wouldn't it find deftask in bake.core ?

10:55 fliebel: LauJensen: It's actually cake.core, but still, no idea.

10:56 LauJensen: One moment… It's even weirder.

10:57 What is the difference with bake vs cake anyway? It's totally mixed up.

10:57 LauJensen: cake is the outer vm, bake is your projects vm

10:57 defn: cake is tasty

10:58 Raynes: I like pound cake.

10:58 fliebel: (hey defn)

10:58 defn: (hey pepijn)

10:58 want a peice of cake?

10:58 piece*

10:59 fliebel: defn: nah, I've had enough (of) cake… It's not working for me

11:00 defn: er uhh emmm, can you show me what you're trying to do and ill ask ninjudd about it?

11:01 Raynes: fliebel: There is a #cake.clj channel here on freenode as well.

11:01 LauJensen: defn: its not cake thats broken, its his macro which wraps cake

11:01 fliebel: Raynes: Great :)

11:01 * Raynes notes that ninjudd hasn't been there in a couple of days, but lancepantz is around sometimes.

11:02 LauJensen: Raynes: ninjudd is working towards a deadline at work which is about 2 weeks out AFAIK

11:02 Raynes: Understandable.

11:02 fliebel: LauJensen: Yea, but my macro just wraps a working deftask and replaces 2 values.

11:02 Raynes: He's a ninja.

11:02 LauJensen: Raynes: true.. so he might actually be in here

11:03 fliebel: its still your macro

11:04 fliebel: LauJensen: When I expand the macro it does bake.core/deftask bit when I run the task it says ClassNotFoundException: cake.core

11:10 defn: fliebel: you're putting this task in your project.clj?

11:11 fliebel: defn: Yea...

11:11 defn: my advice: don't.

11:11 fliebel: defn: so where to move them?

11:11 defn: put it in a tasks.clj and also -- i think something changed recently with cake's namespaces

11:11 because i was mucking with it last night and couldn't find a cake.core either

11:12 you need to make sure to (:use cake) there

11:12 LauJensen: defn: When I spoke with ninjudd about this, we only discussed having tasks in project.clj, something changed since 2 weeks ago ?

11:12 defn: it weas my understanding that they could be in both places since the beginning

11:12 fliebel: defn: So both cake and cake.core need to be used?

11:13 defn: fliebel: truthfully with the latest on github i dont know the answer to that definitively -- but i had trouble making tasks work in my project.clj when i tried out cake about a month ago, and i opted to put them in a tasks.clj in my src/foo/tasks.clj

11:14 and used cake, cake.core there

11:14 although as of last night, when i went to use cake.core -- it no longer was around -- there was a cake.project and cake.server, but neither contained deftask

11:14 so im not sure without talking to lance or ninjudd

11:14 fliebel: defn: I'll try

11:14 octe: i'm trying to define a multimethod where the dispatch function is a keyword, like in the examples you see everywhere.. the problem is when my functions use more arguments than the first map

11:14 how would i create multi functions like that?

11:15 fliebel: defn: You know anything about command args? The readme says something about a mysterious opts var.

11:16 mrBliss: fliebel: maybe this helps: http://stackoverflow.com/questions/1341154/building-a-clojure-app-with-a-command-line-interface

11:18 fliebel: mrBliss: Thank you, but I'm trying to use Cake.

11:18 Raynes: octe: http://gist.github.com/577445 Here is a little example.

11:19 naeu: What's the most idiomatic way of taking a sequence and turning into a map where the keys are the els of the seq and the vals are the els passed through a given fn?

11:20 mrBliss: naeu: something like (zipmap els (map fn els)) or (memoize fn) (lazier than the other)

11:21 octe: Raynes, thanks

11:21 sproust: I shouldn't code Clojure on the weekends, it makes coming back to my day job more difficult every monday. C-M-x, C-M-x, C-M-x, C-M-x and nothing happens. C-M-x ...

11:21 Raynes: octe: All I'm doing there is creating a function that just discards the rest of the arguments.

11:21 defn: fliebel: i dont know much about command args -- i just tried http://github.com/ninjudd/cake/blob/master/examples/test/project.clj and used the example

11:21 it seemed to work fine for me in project.clj

11:22 raek: naeu: this is what I probably would do: (into {} (for [elt some-seq] [elt (f elt)]))

11:22 the zipmap way looks a bit cleaner though...

11:22 fliebel: defn: The readme said nothing about the asteriskses… *opts* vs opts

11:23 LauJensen: a lot cleaner, but a little slower I think

11:23 naeu: mrBliss: raek: Thanks both look nice

11:25 LauJensen: ,(time (dotimes [_ 1e6] (let [x [1 2 3]] (zipmap x (map inc x)))))

11:25 ,(time (dotimes [_ 1e6] (let [x [1 2 3]] (into {} (for [e x] [e (inc e)])))))

11:25 clojurebot: "Elapsed time: 7741.846 msecs"

11:25 "Elapsed time: 7458.186 msecs"

11:25 naeu: LauJensen: not too much difference then

11:26 defn: fliebel: you should add an issue for them to fix that

11:26 :)

11:26 LauJensen: naeu: No, but it depends on the size of your collection. (map inc) spawns an entire new collection of the same size, where the for loop doesn't have that step, but I would go with the first

11:26 unless performance really matters

11:27 fliebel: defn: It works fine in tasks.clj now.

11:27 defn: cool!

11:27 naeu: LauJensen: when you say that (map inc) spawns an entire new collection, is that true even when it's lazy?

11:28 LauJensen: yea, the lazy-ness just determines when it happens, but it will happen

11:28 raek: maps (the data structure) are not lazy, so the whole lazy seq will be forces (as will the for seq)

11:29 but maybe the head of the for seq will not be retained

11:31 into is basicaly just a (reduce conj ...), so the whole sequence generated by for should not be retained, afaik

11:31 ,(source zipmap)

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

11:32 raek: anyway, they seem to be fairly equivalent... choose the one that you think looks prettiest :)

11:32 naeu: raek: that'd be zipmap :-)

11:33 but that's probably because I'm still not entirely comfortable with list comprehension

11:33 right, I'm off out to buy flowers

11:33 thanks for your help everyon :-)

11:46 LauJensen: ~source zipmap

11:46 raek: there's your syntax ^^

12:40 anonymouse89: anyone familiar with the state of complex numbers?

12:40 that is, clojure.contrib.complex-numbers

12:47 I'm trying to do matrix multiplication where the terms of the matrix is like e^ik where k is a constant

12:57 naeu: hey there, I'm sure I'm doing something incredibly stupid, but would totally benefit from some insight

12:58 consider the following fn: (defn tutu [_] (println "road") (java.lang.Thread/sleep 1000) (println "toad"))

12:58 if executed like this: (tutu nil) it prints road, waits, then prints toad

12:58 however, things aren't so simple from within an agent:

12:59 (def a (agent nil)) (send-off a tutu) ;=> doesn't work as expected

12:59 am I doing anything obviously stupid?

13:00 hoeck: naeu: are you using slime?

13:00 ninjudd: LauJensen, defn: looks like fliebel is gone now, but in answer to your earlier question, you can put tasks in PROJECT_DIR/project.clj or PROJECT_DIR/tasks.clj

13:01 naeu: hoeck: yup

13:01 hoeck: naeu: slime does only print stuff in the simple-repl from within the repl thread

13:01 ninjudd: LauJensen, defn: i just recommend that you put them in tasks.clj if you want to maintain lein compatibility

13:01 hoeck: naeu: try to look at your *inferior-lisp* buffer

13:02 naeu: hoeck: I don't believe it's a printing problem - outside of the agent I see the printouts

13:02 yet when I run the fn from within the agent, then I don't

13:02 hoeck: naeu: but the fn is executed in another thread of the agent threadpool, and therefor not printed

13:03 naeu: hoeck: that makes sense. However, the main aim wasn't to print, that was just the example I used here. The main aim is to send bits down a wire, and that doesn't seem to work either

13:03 whereas outside of the agent it does

13:05 hoeck: naeu: regarding the print, maybe try it on a plain repl then

13:06 naeu: maybe can you paste the code that is not working as expected?

13:06 naeu: hoeck: (send-off (get spirits [1 1]) (fn [_] (do (poly/led-on 1 1) (java.lang.Thread/sleep 100) (poly/led-off 1 1))))

13:07 poly/led-on looks up an atom in the poly namespace and calls an external function with the deferenced atom as the first param which then sends some bits down a serial connection

13:07 this all works find outside of an agent

13:08 hoeck: mhh, which IO-lib are you using for the serial connection?

13:09 naeu: rxtx

13:09 jkkramer: naeu: does this work? (future (poly/led-on 1 1) (java.lang.Thread/sleep 100) (poly/led-off 1 1))

13:10 naeu: jkkramer: perfectly...

13:10 jkkramer: naeu: are you sure (get spirits [1 1]) returns an agent?

13:11 naeu: jkkramer: yep..

13:11 (class (get spirits [1 1])) ;=> clojure.lang.Agent

13:13 hoeck: naeu: and the agent is without errors?

13:13 naeu: does a future explicitly create a new thread or does it use a thread from a threadpool?

13:13 hoeck: (agent-error (get spirits [1 1])) ;=> nil

13:13 jkkramer: naeu: it uses the agent thread pool i believe

13:14 naeu: jkkramer: ah, shame - I need an explicit thread

13:14 perhaps I should be creating them myself them

13:15 I just thought it would be nice to use agents as with send-off you can specify an explicit thread and they all have message queues which would be useful

13:16 I just don't know why poly/led-on works on it's own, within a future, within an explicit thread (.start (Thread. #(poly/led-on 1 1)) yet not from within an agent...

13:17 LauJensen: ninjudd: alright, thanks for weighin in

13:17 ninjudd: LauJensen: ah, just sent you an email

13:17 LauJensen: just got it :)

13:17 ninjudd: LauJensen: i think it explains the problem fliebel had with his macro

13:18 LauJensen: Yea, it sounds right

13:19 ninjudd: he can likely fix it by replacing deftask with ~'deftask

13:19 though generally, i'd recommend against wrapping deftask in macro like that unless there is a very good reason

13:20 LauJensen: IIRC thats what I said as well

13:21 ninjudd: wrapping bake may be a little more reasonable, but still bake is pretty terse, and having the namespace forms right there where they are used is a good thing in my opinion

13:22 LauJensen: I've had no problems with it and if you design around it you don't need macros for any use-case I can think of

13:27 jkkramer: naeu: future and send-off use the same executor. it's strange the latter doesn't work

13:27 naeu: jkkramer: so send-off uses a thread-pool too?

13:28 o

13:30 chouser: yes. when a send-off completes, the thread that was running it is available again for another send-off

13:32 naeu: chouser: if I have n agents and I call n send-offs (one to each agent) simultaneously, will that create/utilise n threads?

13:33 chouser: naeu: yes

13:33 assuming none of the send-offs complete before you're done with all the send-offs.

13:33 naeu: chouser: sure

13:35 chouser: would you have any idea why a fn that performs serial IO would work stand-alone, from within a future, from within an explicitly created thread, but not from within an agent (and also not generate errors)?

13:35 chouser: how sure are you that it doesn't generate an error. :-)

13:35 fns you send to an agent need to take the agent's old value as their first arg

13:36 naeu: chouser: only as sure as I am of agent-error reporting it to me

13:36 chouser: yeah, my fn is defined as follows:

13:36 (defn howdy [m] (do (poly/led-on 2 2) (Thread/sleep 5000) (poly/led-off 2 2)))

13:37 chouser: that do is superfluous.

13:37 but not your problem. hrm.

13:38 naeu: The side effect is usually obvious - a light shines on an external device then extinguishes

13:38 however, from within the agent I have no illumination to enjoy

13:39 chouser: (send-off (agent nil) howdy)

13:39 like that?

13:39 naeu: chouser: precisely

13:39 chouser: I got nuthin' Works here for println.

13:39 naeu: yeah, works here for println too

13:40 oddly, (future (poly/led-on 1 1) (java.lang.Thread/sleep 1000) (poly/led-off 1 1)) works fine

13:40 chouser: you said future works? how do you call it?

13:40 :-)

13:41 what about (do (future (howdy nil)) nil)

13:42 naeu: chouser: works just like Blackpool illuminations :-)

13:42 I wonder why future works and send-off doesn't

13:42 chouser: yeah, me too

13:43 quite a bit more mechanics inside agents

13:43 naeu: the mechanics behind poly/led-on are probably unecessarily complex

13:44 but one would assume that the side-effect behaviour of a future be similar to that of an agent

13:45 I guess I'll have to build an agent-like entity myself with n queues and n threads working on the queues

13:45 raek: using agents should work. something's very strange.

13:46 LauJensen: naeu: One of the things which can be tricky about agents is that they can die in silence. Did you check out the new error handling stuff?

13:46 hoeck: naeu: is the io lib threadsafe? do you have a link to the sources?

13:46 naeu: LauJensen: agent-error returned nil

13:46 mrBliss: naeu: you haven't issued a (shutdown-agents)?

13:47 chouser: naeu: (send-off (agent 1 :error-handler prn) howdy)

13:47 naeu: hoeck: I don't think that the io lib is at all threadsafe. However, I wrap the lib with another agent to serialise the calls

13:48 mrBliss: why would I need to issue a (shutdown-agents)?

13:48 mrBliss: If your agents went berserk (you couldn't stop them or something)

13:48 you would have to restart your repl to get them running again

13:48 jkkramer: naeu: have you checked for errors in that lib-wrapping agent?

13:48 chouser: that would kill future too

13:49 (shutdown-agents) would kill future too

13:49 naeu: did you see that :error-handler example? can you try it?

13:49 naeu: chouser: specifying the :error-handler made no difference

13:49 mrBliss: chouser: ok

13:50 naeu: the call ran, but no beans

13:50 chouser: naeu: can you do a println deep in your led-on fn?

13:50 naeu: just to see if led-on is executed?

13:51 chouser: right

13:51 preferrably as deep as you can insert a println

13:51 to make sure that led-on is called, but also whatever *it* calls is

13:51 ...

13:51 I got it.

13:51 you said you're using *another* agent inside?

13:51 naeu: chouser: yes..

13:52 do they not compose?

13:52 chouser: sends in agent actions are held until the action completes

13:52 so you're probably sending the on and off more or less simultaneously after 5 seconds

13:52 sufficiently deep printlns would show that.

13:52 naeu: chouser: ah bugger

13:53 chouser: so try...

13:53 naeu: working on it...

13:54 chouser: as a quick hack, try (release-pending-sends) right before the Thread/sleep

13:54 naeu: chouser: your assumption appears to be entirely accurate

13:55 chouser: also, the release-pending-sends hack works

13:56 chouser: so can you briefly summarise what's going on when you compose agents?

14:02 raek: the transition functions of agent either fail or succeed. sends only really gets sent if it succeeds (does not throw an exception)

14:03 sends in transactions behave this way to

14:03 o

14:03 naeu: yeah, I think I grok it now

14:03 so I'm wondering about the best way to proceed

14:03 is it wise to wrap the non-threadsafe IO lib with an agent?

14:04 or is there a better way to do this?

14:04 raek: if you want to serialize access, agents sounds resonable

14:04 naeu: raek: yeah, that's the intention

14:04 mrBliss: I built a similar system once with agents and promises

14:04 hoeck: naeu: not if you want thread confinement, because agent-actions are invoked in many pool threads

14:05 raek: imho, agents and shared output (any write-only operation) go together well

14:05 naeu: hoeck: what do you mean by thread confinement, and what might a potential issue be?

14:06 hoeck: that means you only invoke your lib methods from within a single thread

14:06 naeu: however, if i do use an agent, do I have to litter my code with release-pending-sends to make sure the messages get sent if the IO is initiated in an outer agent?

14:07 chouser: another option is to dedicate a thread to consuming a BlockingQueue

14:07 naeu: hoeck: I thought that with agents, if you invoke it from multiple threads then the messages get queued up and only consumed sequentially...

14:07 chouser: then you can toss :on and :off events into it whenever you want.

14:07 naeu: the latter is true, that's how agents work.

14:08 raek: naeu: only if that code happens to be inside an agent function

14:08 naeu: raek: so I don't fully understand the thread confinement problem

14:08 raek: then the writer of the agent function should be aware of this behaviour anyway

14:08 hoeck: naeu: yes, but the libs methods are invoked from many different threads, and without proper synchronisation there is no guarantee that one thread reads the values set by another

14:08 lyle: By any slim chance, is anyone associated with the RubyLearning "Clojure for Beginners" course in the channel?

14:09 naeu: hoeck: all the libs methods can only be accessed via one agent

14:09 which acts as a gatekeeper

14:09 Raynes: lyle: I'm a mentor.

14:09 Anything I can help you with?

14:09 hoeck: naeu: I'd second what chouser said, just build a dedicated IO thread and use a Loop and a BlockingQueue to consume and invoke functions

14:09 naeu: hoeck: cool

14:09 Thanks everyone for your insight and advice

14:10 lyle: Raynes: The link to the first day's exercise is broken. Several of us now have posted about it to the forum but no fix as of yet.

14:10 Raynes: lyle: Hrm. I didn't get any notification emails about it. I'll check it out.

14:10 naeu: I'm sure my objectives may seem strange and usual - but I'm trying to use Clojure to build a musical instrument, so things like timeliness matter in a different way to me :-)

14:10 chouser: naeu: but agents are really for managing shared state

14:11 lyle: Raynes: To be clear, I'm talking about the link to "Exercise 1: Clojure Syntax", at the bottom of this page: http://rubylearning.org/class/mod/resource/view.php?id=2025

14:11 raek: I've started programming on a lib for making BlockingQueue more clojure-y, btw: http://github.com/raek/stream-seq

14:11 naeu: chouser: I guess I was being too general when I saw the lib functionality as 'shared state'

14:11 lyle: Raynes: And the discussion is here: http://rubylearning.org/class/mod/forum/discuss.php?d=4194

14:12 chouser: naeu: they also serialize events, and manage thread pools. But sometimes when you want some of those feature but not all of them, agents end up behaving in ways that are unhelpful.

14:12 ...like holding your sends.

14:12 naeu: damn them for holding my sends! :-)

14:12 chouser: (send (agent nil) ...) the 'nil' there is a little clue you might be abusing your agent.

14:13 naeu: For thy who witholdeth my missives shall be subject to my fullest wrath

14:13 chouser: if the state of the agent doesn't matter, perhaps something else would make more sense.

14:13 naeu: chouser: yep, you're absolutely right :-)

14:13 thanks again

14:14 chouser: if you have one or more threads blocking, trying to pop from a work queue, agents are wrong and you should try a BlockingQueue

14:14 I believe I wrote that somewhere once...

14:15 Raynes: lyle: All of the exercise links appear to be broken. I'll fix them. I'm very, *very* sorry about this. I would have fixed it immediately if I had gotten an email notification.

14:16 lyle: Raynes: It's OK! I'm just glad I was able to track someone down. ;)

14:16 chouser: ah yes, chapter 11 section 3, "When not to use Agents" :-)

14:17 lyle: Raynes: I have noticed that email notifications from the RubyLearning site are a little slow. It's a long way for those packets to get here all the way from India, I guess.

14:17 naeu: chouser: I haven't got that far yet ;-)

14:17 Still working my way through chapter 10

14:19 kumarshantanu: hi, can somebody tell me how to define test-ns-hook for multiple test files?

14:19 raek: chouser: I discovered that som of the macros of error-kit is missing from the docs: http://clojure.github.com/clojure-contrib/error-kit-api.html

14:20 chouser: naeu: fair enough. I'll let you catch up then. :-)

14:20 raek: it probably isn't you that I should report this to, anyway...

14:20 chouser: raek: how would you feel if the error-kit api changed?

14:21 raek: my intention was to try if the continue stuff would make sense in my project

14:21 I want to do error handling in ring handlers

14:22 so something that returns an error response instead of throwing an exception might interesting

14:22 Raynes: lyle: Thank you very much for letting me know. :\

14:22 chouser: raek: ok, cool. let me know how it goes.

14:22 raek: what would the API change be? remove the continue stuff?

14:22 chouser: raek: pay particular attention to whether there's any value in a hierarchy of error types, or if simple "tags" work better.

14:23 raek: no, simplify the error object/type stuff

14:23 raek: is there anywhere I can read more on how continue is used?

14:23 continue-with just return a value at the "raise-point", right?

14:24 lyle: Raynes: Thank you. Now I realize that I had already found the exercise by accident, although I didn't know that was "the" exercise. ;) I thought it was just some sort of follow-up discussion of the exercise. Thanks again for your help!

14:25 Raynes: lyle: I'm not sure what all that FORUMDISCUSSION nonsense was. I just put in direct links. I'm new to this mentoring stuff.

14:26 lyle: Raynes: Presumably some sort of template variables that weren't being replaced properly, but I don't know (not a PHP person myself).

14:26 chouser: raek: yes

14:26 Raynes: I'm sure they'll educate me.

14:26 chouser: raek: http://pragprog.com/magazines/2009-07/when-things-go-wrong

14:28 raek: chouser: I used error-kit as a replacement for exceptions once. I did not use the type hierarchy thingy then. I declared the errors hierarchically, but did not utilize it in the handlers

14:29 thanks for the link!

14:29 chouser: without a hierarchy, you might not need to declare error types at all

14:29 sure, I love that link -- Halloway documenting and demoing my code, so I don't have to. :-)

14:30 raek: a (namespace qualified) keyword for identifying the error would be sufficient for me, I believe

14:30 kumarshantanu: hi, can somebody tell me how to define test-ns-hook for multiple test files (namespaces)?

14:36 raek: ~conditions

14:36 clojurebot: CL conditions is http://www.gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html

14:36 raek: ~error-kit

14:36 clojurebot: Excuse me?

14:37 raek: clojurebot: error-kit is http://pragprog.com/magazines/2009-07/when-things-go-wrong

14:37 clojurebot: Alles klar

14:37 chouser: error-kit is based almost exclusively on that gigamonkeys page

14:45 LauJensen: always good to base your work off monkeys

14:45 raek: where does bind-continue return from? the raise-point or the handle-point?

14:47 chouser: ummmm

14:48 raek: this calls for experimentation at the repl, anyway

14:49 chouser: I think the final value of a bind-continue clause is the return value of the whole with-handler. Is that what you're asking?

14:50 raek: yes

14:50 but I should be able to end the bind-continue form with a continue-with I guess...

14:51 chouser: man, that stuff's complicated. I think I had forgotten about bind-continue

14:53 I don't think you can continue-with from inside a bind-continue

14:53 raek: my idea was to define stuff that can go wrong in the model as errors

14:53 chouser: though tell me if you find it works.

14:53 raek: code that renders an error response as bind-continues

14:53 and connect these with handlers that call continue

14:54 (handle form-validation-error [details] (continue bad-request details))

14:55 but just a handler would be sufficient, I think

14:55 chouser: I think when you call 'continue' control is irrevokably passed up to whereever (bind-continue bad-request ...) is

14:56 so no way to do a continue-with

15:01 LauJensen: I vaguely recall some kind of Swing Utility, or Refinery, or something similar which lets you center a jframe on the screen (dont need tips on writing it myself, just wanted to know if something exists already)

15:04 raek: chouser: yes, you're right.

15:05 ordnungswidrig: LauJensen: java.awt.Frame/setLocationRelativeTo(null)

15:05 chouser: but regardless of whether it's possible, if simply calling a fn to render an error is sufficient, then that's certainly simpler.

15:05 LauJensen: ordnungswidrig: thanks I'll have a look

15:06 ordnungswidrig: LauJensen: but you're right, there are quite a lot of helper that do this. It's nicely hidden in the api doc

15:07 raek: is bind-continue supposed to be provided by the raiser or the handler?

15:08 cemerick: LauJensen: just use jframe.setLocationRelativeTo(null)

15:09 chouser: something in the middle, I think. the raiser provides only the error. a handler up above uses continue to send control from the raiser partway up to the bind-continue.

15:09 gotta go. bbl.

15:11 raek: ok, thanks! I will continue to experiment with this

15:49 arkh: re-seq says it returns a lazy-seq but it actually doesn't. Anyone know why?

15:49 ,(prn (class (re-seq #"(a)(s)d" "asdf")))

15:49 clojurebot: clojure.lang.Cons

15:49 arkh: ,(prn (class (for [i (range 10)] [i])))

15:49 clojurebot: clojure.lang.LazySeq

15:52 pomyk: ,(prn (class (rest (re-seq #"(a)(s)d" "asdf"))))

15:52 clojurebot: clojure.lang.LazySeq

15:54 raek: ah, since it knows whether the first cell is nil or not, it might as well return it

16:17 dsantiago: Does anyone have any strategies for easily building your programs in different configurations? (Like, debug/release)

16:25 lancepantz: dsantiago: i've actually been working on that exact feature for cake

16:26 i have it working in a branch if you're feeling adventurous

16:26 you'd ofcourse have to be using cake for your builds, which again is for the adventurous :)

16:36 amalloy: i'm a bit surprised that it's tricky to combine update-in and remove. is there anything better than (update-in mymap [:key1 :key2] #(remove #{item} %))? ideally i could just end with remove #{item}

16:37 raek: you have a map of maps of sequences?

16:45 amalloy: yes

16:46 raek: since you seem curious, it's a card game thing. there is a map of players, each of whom has a map of suits, whose values are vectors of cards

16:46 raek: I would make the vectors sets

16:47 since they have fast add and remove operations

16:47 but you still get the rather long update-in

16:47 amalloy: hm. that's a good point. i was using vector for sorting, but isn't there a sorted-set?

16:47 raek: yes, there is

16:48 and you can provide your own comparator if you want to sort them like 1 2 3 ... 10 :j :q :k

16:48 dsantiago: lancepantz, how do I find this branch?

16:48 amalloy: yeah, i've already got a comparator

16:48 thanks for the tip! but beware, you're teaching me that it's a good idea to just spew random crap about my app into #clojure and hope someone will improve it :)

16:49 lancepantz: dsantiago: http://github.com/ninjudd/cake/tree/f

16:49 raek: (update-in [player suit] #(disj % rank))

16:49 lancepantz: dsantiago: i'll throw a gist together that shows how to use it, just a second

16:50 dsantiago: Thank you.

16:51 raek: oh, forgot the map as the first argument to update-in...

16:52 lancepantz: dsantiago: http://gist.github.com/578019

16:53 dsantiago: lancepantz: So this works with swank?

16:53 Cuz this is like exactly what I wanted.

16:54 lancepantz: dsantiago: the defproject stuff is pretty straight forward, then in tasks you'll have a var called *env* that's bound to the values from the map of your current environment

16:55 you can then set your environment in .cake/config as env=qa or from the command line with -env=qa

16:55 dsantiago: Brilliant.

16:56 lancepantz: cake works with swank, yws

16:56 *yes

16:59 dsantiago: So this is in a branch, so to install it I'm gonna have to do some git-fu?

17:00 lancepantz: yeah, you'll have to clone it, the git co f

17:00 and symlink bin/cake to your path

17:00 s/the/then/

17:01 dsantiago: Thanks.

17:02 How close is this to going into the full version?

17:04 lancepantz: probably a week or so

17:04 dsantiago: Wonderful.

17:04 This finally made me pull the trigger on lein -> cake.

17:05 lancepantz: shhhh :)

17:06 dsantiago: Heh. I like them both. But this one is solving my biggest pain point right now.

17:06 grignaak: is there any reason conj isn't implemented as such: http://pastie.org/1156631 ?

17:07 lancepantz: great! it was a pain for me as well, glad it helps others

17:07 grignaak: it would make it a lot easier for (apply conj coll possibly-empty-coll)

17:07 lancepantz: s/pain/pain point/

17:07 sexpbot: <lancepantz> great! it was a pain point for me as well, glad it helps others

17:08 alpheus: I've got some awkward code that I think could be improved with destructuring but I don't know how. If you'd like to take a look: http://upholsters.us/pairs-to-map-of-sets.clj

17:12 jkkramer: grignaak: (reduce conj coll possibly-empty-coll) or (into coll possibly-empty-coll) are alternatives

17:14 grignaak: great! thanks! I had a simple two-line implemented a conj+ that forwarded to conj

17:15 but into looks to fit the bill nicely

17:17 amalloy: alpheus: i think you want to use language built-ins like reduce here, rather than write it yourself

17:18 jkkramer: ,(reduce (fn [m [k v]] (assoc m k (conj (get m k #{}) v))) {} [[:bob :beer] [:bob :bread] [:alice :apples]])

17:18 clojurebot: {:alice #{:apples}, :bob #{:bread :beer}}

17:19 jkkramer: alpheus: ^^

17:19 amalloy: (defn make-sets [& pairs] (reduce (fn [master [who what]] (update-in master [who] conj what)) {})) is my version; it works but winds up with seqs rather than sets at the end

17:20 i didn't know about the not-found feature of maps, jkkramer! neat!

17:22 lpetit: Hello

17:23 raek: ,(:test {} :not-found)

17:23 clojurebot: :not-found

17:23 jkkramer: ,(reduce (fn [m [k v]] (update-in m [k] (fnil conj #{}) v)) {} [[:bob :beer] [:bob :bread] [:alice :apples]]) ; also possible

17:23 clojurebot: {:alice #{:apples}, :bob #{:bread :beer}}

17:24 jkkramer: update-in + fnil can be handy

17:24 raek: didn't know about fnil... neat!

17:25 (fnil re-find "")

17:26 jcromartie: wow fnil is blowing my mind

17:26 alpheus: thanks, all. I'll look at those and learn.

17:26 jkkramer: clojure.core is a treasure trove :)

17:27 phobbs: wow

17:29 raek: clojure's function-returning functions are often overlooked...

17:30 juxt is a recently found favourite of mine

17:30 jcromartie: nifty

17:31 raek: ,(let [stack [1 2], pop-peek (juxt pop peek), [stack arg1] (pop-peek stack), [stack arg2] (pop-peek stack)] (conj stack (+ arg1 arg2)))

17:31 clojurebot: [3]

17:32 jkkramer: one of my favorite snippets -- run-length encoding:

17:32 ,(map (juxt first count) (partition-by identity [:a :a :a :b :b :c :d :d]))

17:32 clojurebot: ([:a 3] [:b 2] [:c 1] [:d 2])

17:33 raek: man, that's beautiful...

17:36 jcromartie: true dat

17:39 * jkkramer is now even more depressed to be coding in php

17:41 talios: Awesome - writing IntelliJ IDEA plugins in clojure - http://bit.ly/9Zaynf

17:44 lpetit: talios: interesting, but it's somewhat not new that genclassed clojure is fully interoperable with pure java compiled code, or is it ?

17:45 hmmm, maybe I missed the point ...

17:53 amaevis: Hi! Could someone help with interpreting how LockingTransaction.run() works?

17:53 I'm trying to create a version of refs with built in durability

17:55 Has there been any work with adding D to ACI identities?

17:56 chouser: there have been a couple threads on the google group

17:56 amaevis: I think that's me.

17:56 chouser: :-)

17:57 amaevis: I'd like to get your thoughts...

17:57 Is it worth pursuing? Part of the vision?

17:57 talios: hrm - lpetit left - oh well, what was more interesting is that Jetbrains are looking at writing plugins in clojure as part of the plugin code - even if just genclassed currently

17:57 chouser: the vision isn't mine

17:58 I don't know what's in rhickey's head.

17:59 amaevis: You've been contributing a lot longer. :)

17:59 chouser: I would love a simple and efficient way to persist in-memory structures to disk.

17:59 I don't know if I like the idea of transactions blocking until the disk flushes, though.

18:00 amaevis: Does the API I put forth on Google Groups make sense?

18:00 It doesn't have to block to the disk flush.

18:00 chouser: without that it's not Durable, is it?

18:01 amaevis: I happen to be using BDB and that param is configurable.

18:01 You can choose your durability level.

18:01 By default it would flush per transaction.

18:03 chouser: what would be the value of tying into the STM except to flush per transaction?

18:03 I'm not seeing your API on the group.

18:04 bartj: very off-topic, but does anyone have a statistics background here

18:05 amaevis: The API is basically to use (dref <name> <initVal>) instead of (ref <initVal>).

18:05 It ties the contents of the durable ref to the <name> in the BDB store.

18:05 amalloy: bartj: i took one graduate course in statistics but it's been a long time since i used any of it

18:05 amaevis: Clojure would flush to the DB with every transaction.

18:06 But the DB can choose to flush to disk at will.

18:06 By default, at the highest durability, it would flush per transaction.

18:06 But it can write to log without flushing to the main pages.

18:07 Or delay writing to log altogether.

18:07 bartj: the question basically is about generating a representative sample of (~400) from 400K records

18:07 amaevis: If performance requires it. It's a conscious choice by the app dev to offset durability for performance.

18:11 chouser: amaevis: Each ref would be in its own file?

18:11 amaevis: No, it's a key-value pair in a BDB DB.

18:11 The key is given at create time.

18:12 raek: bartj: have you seen the Incanter project?

18:12 amaevis: When the same code is run later (i.e. next JVM instance), using that same key inits the dref from disk. Only if it's not found does the code-supplied initVal get used.

18:12 chouser: so two transactions operating on two different refs that would normally have essentially no contention will now contend over access to the db?

18:12 raek: ...maybe you were looking for a person with knowledge rather than a library

18:12 bartj: raek, yes (but not thoroughly), the question is more whether the approach is correct

18:13 raek, yes your are right

18:13 amaevis: Yes. I see that as a plus. Two JVMs accessing the same BDB DB and key get sync-ed.

18:13 chouser: amaevis: have you looked at http://github.com/gcv/cupboard

18:13 amaevis: Yes. I don't like explicit (make-instance) calls.

18:13 Plus there's no transactional safety.

18:14 * chouser nods

18:14 chouser: hm, it does claim "ACID transactional semantics"

18:14 amaevis: Yes, within a single call.

18:15 chouser: ok

18:15 amaevis: But how do you compose?

18:15 chouser: sounds to me like you've got more bases covered than I know to look for.

18:16 amaevis: I have the implementation all set except for hacking the commit into LockingTransaction.

18:16 I don't grok run().

18:16 I see the commutes, sets, and vals collections.

18:17 But I'm unclear as to how to determine refs that have been ensured without setting, ref-sets without ensures, and alters.

18:17 As well as commutes, which I don't grok at all.

18:19 chouser: well, I may be able to help you with those details later.

18:19 but for now I have to go.

18:19 fare well.

18:19 amaevis: thanks!

18:22 raek: the implementation of commute or what it's about?

18:22 amaevis: the implementation

18:23 within the context of the run() method.

18:23 raek: can't help you there :-)

18:23 amaevis: :)

18:25 anonymouse89: is there a more concise way to do this? (assoc foo :elts (concat (foo :elts) (list a)))

18:26 raek: ,(update-in {:elts [1 2 3]} [:elts] #(conj % 4))

18:26 clojurebot: {:elts [1 2 3 4]}

18:27 raek: vectors are faster for appending to the back

18:28 lpetit: ,(update-in {:elts [1 2 3]} [:elts] conj 4)

18:28 clojurebot: {:elts [1 2 3 4]}

18:28 raek: update-in can assoc a new value to a key by applying a function to the old value

18:28 hrm, of course...

18:28 lpetit: no need for #(conj % 4), conj 4 is sufficient with update-in and al

18:29 but I'd better go to bed now, cu

18:29 anonymouse89: raek, lpetit: perfect

18:39 bartj: raek, is it possible to sample a distribution in Incanter ala - http://www.exposurescience.org/heR.doc/library/heR.Misc/html/distrib.html

18:40 amalloy: yep, if two people give identical answers within seconds of each other, it's a good bet the answer is right :)

19:00 is there a nice way to filter a seq of maps for values that have some given value? (filter (comp #{testval} :key) myseq) seems good but i wonder if it's idiomatic

19:01 lazy1: "values that have some given value?" I don't understand

19:02 amalloy: er...entries with a given value? ie i only want objects whose :name property is "David"

19:03 tomoj: looks good to me

19:04 amalloy: neato. i'm still getting my head around the idea of using objects as functions; i expect the ClassCastPolice to jump around the corner when i pass a set to comp

19:08 lazy1: amalloy: (filter #(= (:key %) some-value) myseq) will work as well

19:08 Not sure if it's more idiomatic though

19:14 jjido: how do I add one element in front of a vector or list?

19:15 AWizzArd: jjido: conj

19:16 jjido: ,(conj "a" [2 3 4])

19:16 clojurebot: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IPersistentCollection

19:16 jjido: ,(conj ["a"] [2 3 4]

19:16 clojurebot: EOF while reading

19:16 jjido: ,(conj ["a"] [2 3 4])

19:16 clojurebot: ["a" [2 3 4]]

19:16 jjido: I need to flatten it

19:17 AWizzArd: (conj yourlist new-item)

19:17 lazy1: ,(cons 4 [1 2 3])

19:17 clojurebot: (4 1 2 3)

19:17 AWizzArd: ,(conj (list 10 20 30) :x)

19:17 clojurebot: (:x 10 20 30)

19:18 AWizzArd: ,flatten

19:18 clojurebot: #<core$flatten clojure.core$flatten@c09e0f>

19:18 jjido: thanks you two

19:18 lazy1: ,*clojure-version*

19:18 clojurebot: {:interim true, :major 1, :minor 2, :incremental 0, :qualifier "master"}

19:18 lazy1: Note that for vector, conj will append

19:18 ,(conj [1 2 3] 4)

19:18 clojurebot: [1 2 3 4]

19:24 jjido: to take all elements from list up to item n? to take all elements from item n upwards?

19:25 AWizzArd: jjido: .subList

19:26 jjido: AWizzArd: if it starts with . it is Java isn't it?

19:27 Ok it is documented in the Sequences page

19:27 lazy1: ,(doc take)

19:27 clojurebot: "([n coll]); Returns a lazy sequence of the first n items in coll, or all items if there are fewer than n."

19:27 lazy1: ,(doc drop)

19:27 clojurebot: "([n coll]); Returns a lazy sequence of all but the first n items in coll."

19:28 jjido: and:

19:28 ,(doc split-at)

19:28 clojurebot: "([n coll]); Returns a vector of [(take n coll) (drop n coll)]"

19:31 jjido: do names need to be unique in a let?

19:31 ,(let [a 2, a (+a a)] a)

19:31 clojurebot: java.lang.Exception: Unable to resolve symbol: +a in this context

19:31 jjido: ,(let [a 2, a (+ a a)] a)

19:31 clojurebot: 4

19:31 jjido: cool

19:56 Does Clojure come with a math-specialised library?

19:57 lazy1: Like http://incanter.org/ ?

19:57 You have access to all the Java Math library

20:01 ,(.isProbablePrime (bigint 10001) 10)

20:01 clojurebot: false

20:02 killown: clojure is a good option for those who want start with a functional programming language?

20:02 dnolen_: killown: depends on what you want to explore, but I would venture a yes.

20:05 killown: dnolen_, just for know, I want one that offer best concepts of a functional language.

20:06 dnolen_: killown: unsure about "best concepts". for example, Haskell has different concepts than Clojure. From what I can tell, they're "different" not "better"

20:06 jjido: killown: Clojure is v. good, it is based on Lisp which has been around for a long time

20:06 the syntax is simple!

20:07 killown: dnolen_, jjido I want one with simple syntax :)

20:07 Raynes: Lisp is well known for it's (lack of) syntax.

20:08 jjido: lazy1: it is certainly there in incanter but I don't know how to find it. I want to get all permutations of a list

20:08 killown: dnolen_, but I need one that forced into a functional paradigm

20:08 dnolen_: ,(permutations [1 2 3])

20:08 clojurebot: java.lang.Exception: Unable to resolve symbol: permutations in this context

20:09 dnolen_: ,(clojure.contrib.combinatorics/permutations [1 2 3])

20:09 clojurebot: java.lang.ClassNotFoundException: clojure.contrib.combinatorics

20:11 dnolen_: ,(require '[clojure.contrib.combinatorics])

20:11 clojurebot: java.io.FileNotFoundException: Could not locate clojure/contrib/combinatorics__init.class or clojure/contrib/combinatorics.clj on classpath:

20:11 dnolen_: darn, jjido: anyways, put that into your repl that has contrib on the classpath

20:11 jjido: ok

20:11 dnolen_: killown_: yeah Clojure will push you in that direction.

20:16 killown: dnolen_, thanks

20:34 jjido: ,(fact 10)

20:34 clojurebot: java.lang.Exception: Unable to resolve symbol: fact in this context

20:36 jjido: meh I started with 3 million permutations ;-)

20:37 the fans were blowing hard until I pressed ^C

20:40 gn

20:59 jcromartie: killown: just to chime in, yes Clojure is a good place to start learning FP

21:00 if you never use ref, agent, atom, or def (twice) you're purely functional

21:00 some might say that memoize is cheating

21:00 but I say it still counts

21:00 technomancy: or I/O, or binding, or delay, or promise, or future... =)

21:01 * technomancy won't mention alter-var-root and with-local-vars

21:01 technomancy: </pedant>

21:03 amaevis: how is memoize cheating?

21:03 jcromartie: ,(source memoize)

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

21:03 jcromartie: oops

21:03 well, you get the picture

21:03 yes

21:03 amaevis: lol

21:05 jcromartie: it uses an atom to store the cache

21:07 amaevis: the side effects aren't accessible

21:07 that's fine

21:14 tomoj: it's fine as long as the function you memoize is fine

21:26 jcromartie: ,(let [printer (memoize (fn [x] (println x)))] (printer 1) (printer 1))

21:26 clojurebot: 1

21:26 jcromartie: there are all sorts of ways that memoize could cause surprises

21:27 but anybody writing Clojure understands what mutable state implies

21:27 so it might not be too surprising

22:22 fbru02: what is the actual meaning of splice ?

22:22 `(~@foo) where foo is a local, what does it do?

22:24 lancepantz_: oh, you mean the reader macro?

22:24 wwmorgan: ,(let [foo (list :a :b :c)] `(~@foo))

22:24 clojurebot: (:a :b :c)

22:24 rhudson: The value of foo in such a case is typically a sequence, as (a b c). If you just wrote `(~foo), you'd get ((a b c))

22:24 lancepantz_: it's just like apply

22:24 rhudson: But `(~@foo) gives you (a b c)

22:25 lancepantz_: *correct me if i'm wrong

22:25 fbru02: thanks all, and why is it so relevant to macros ?

22:26 rhudson: A typical use is when you have something like (defmacro f [bindings & body ])

22:26 where you want to have the forms in 'body be the code expansion of the macro

22:26 You don't want extra parens around the body

22:27 fbru02: rhudson: thanks i get it

23:06 ivey: I am having a nasty problem with SLIME. My REPL keeps freezing, and I have to reconnect. Happens almost anytime I leave the window containing the REPL.

23:06 Anyone seen this? Using 'lein swank' for the backend, but that shouldn't matter.

23:07 jcromartie: hm, not me. sorry

23:08 thunk: ivey: Are you able to evaluate compound forms, like (+ 1 2) , before it freezes?

23:08 ivey: let's see

23:09 i can usually do most anything as long as I don't leave the buffer

23:09 although right now i can switch back and forth and it's OK

23:11 feh, of course it stops being a problem when i ask about it.

23:11 thunk: There's another hanging repl issue that can be worked around with an (unlad-feature 'slime-autodoc t) (evaluated by emacs, not slime, that is), but this doesn't sound like it.

23:12 *unload-feature

23:12 ivey: let's see if that makes a difference

23:13 i rarely use the autodocs anyway

23:18 OK, I have more info. turning off autodoc didn't fix it. It's when I switch to a buffer with a clj file that it hangs.

23:19 In the modeline there's a [project-name clojure N] where N is normally not there. hit c-c c-k and N goes to 1, then goes away again.

23:19 but as I move point around the file, N goes to 2, 3, 4...like it's sending requests to swank for some reason

23:20 jlf`: any info when you mouse over N?

23:22 ivey: just minor mode info

23:23 * jlf` was thinking help for minor mode might be illuminating

23:27 tomoj: ,(reduce #(map + %1 %2) (repeat 100000 [1 1 1]))

23:27 clojurebot: Eval-in-box threw an exception:java.lang.StackOverflowError

23:28 tomoj: why?

23:28 clojurebot: http://clojure.org/rationale

23:30 wwmorgan: ,(reduce #(doall (map + %1 %2)) (repeat 100000 [1 1 1]))

23:30 clojurebot: (100000 100000 100000)

23:31 tomoj: yeah, in my case using vect to force worked

23:31 I still don't understand it though

23:32 I think I vaguely understand why it happens. it seems strange to me that I've never seen a blog post about this kind of problem

23:32 wwmorgan: the reduce builds up a lazy sequence whose evaluation requires going up 10000 levels in the stack. When the repl tries to evaluate it, the jvm runs out of stack space

23:32 er, 100,000

23:32 tomoj: yeah

23:33 I don't think I've ever thought about stack being required to realize a lazy-seq

23:33 well, I'll always be able to recognize that stack trace

23:38 ivey: OK, narrowed it down to something in '(slime-repl slime-presentations slime-autodoc)

23:38 my guess is presentations

23:41 Yep, presentations. And since I don't actually know what that's good for...problem solved! Thanks for helping me think out loud.

Logging service provided by n01se.net