#clojure log - Sep 18 2010

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

0:01 technomancy: ah; nice, it just joins it with the line above

0:01 I didn't get that far

0:28 joegallo: tehcnomancy: I'm in your code, making changes.

0:29 Crap, typo. Anyway.

0:29 technomancy: I'm making good progress on your side, I'll send a pull request or something soon.

0:29 Right now I'm dealing with a bizarre emacs error.

0:47 laurus: How difficult is it to make a theme for JFreeChart?

0:52 joegallo: technomancy: Pushed.

0:53 Still some bugs, but I got around the one I was dealing with.

0:56 scottj: laurus: no clue. there don't appear to be many, even outside of incanter. maybe modding the incanter ones would be easy?

0:57 technomancy: joegallo: sweet; thanks

0:57 just added you to the repo so you can push directly for future changes

0:58 laurus: scottj, well, I took a look at charts.clj, but it's hard to figure out what would need to be changed, so I thought I'd ask here to see if anyone else had taken a look at that

0:58 I'm surprised someone hasn't made a simple theme with a white background, etc.

1:06 bhenry: joegallo: technomancy http://gist.github.com/585375

1:08 joegallo: bhenry: :(

1:08 Bleh, I haven't been testing for that.

1:08 bhenry: yeah i was wondering if it was strange for me to use the namespaces that way.

1:09 joegallo: I dunno, I haven't seen it before, but that's neither here nor there.

1:09 If clojure supports it, then I think this should, too.

1:10 bhenry: agreed. works great in my latest project, but i don't have any of those multiple namespaces from the same project dealies.

1:15 joegallo: don't feel too bad. it was wonky before your push too.

1:20 technomancy: I dunno; I read a thread on a future possible overhaul of the ns form and it sounds like the nesting like that may be deprecated in the future

1:21 it'd be nice to support, but I think there's a lot of other low-hanging fruit to tackle first

1:21 like removing unused imports maybe

1:22 bhenry: technomancy: would the removing unused imports be it's own function? sometimes i throw some in knowing i will need them later.

1:23 i wouldn't mind it say right before pushing to production, but if it was part of some bigger function i'd hate to lose important stuff

1:23 technomancy: it would be its own function, yeah

1:23 and it would be paired with a function that could check for imports that are needed but absent and search the classpath for them

1:24 bhenry: cool. i'll have to find those plans for the ns form.

1:24 amalloy: everyone: what's the project y'all are working on?

1:24 bhenry: oh that's a good one.

1:25 technomancy: amalloy: talking about Durendal now: http://github.com/technomancy/durendal

1:26 bhenry: http://groups.google.com/group/clojure/browse_thread/thread/dbcfb0dc6699ec41/e8165da1ceebba9d?#e8165da1ceebba9d

1:26 also http://www.assembla.com/spaces/clojure/tickets/272-load-ns-require-use-overhaul

1:26 amalloy: technomancy: that's no fair. i'm not done learning all the other emacs features yet. can you hold off a decade or so?

1:27 technomancy: nobody learns all the emacs features

1:28 amalloy: that's why i want a decade

1:28 (it's a sort of irony, see)

1:28 laurus: I wonder when someone will write a Clojure version of Emacs :P

1:28 amalloy: laurus: never, i imagine

1:29 laurus: Who knows? :)

1:29 amalloy: well, knock yourself out

1:29 laurus: amalloy, haha, no thanks!

1:29 ;)

1:29 Hence why you said "never" :P

1:32 amalloy: yep

1:33 well, that and there's no compelling reason to do so. if there were a reason, it might happen

1:34 laurus: Right :)

1:36 Good night everyone :)

1:38 amalloy: technomancy: you don't have to escape . inside of [character classes]. you also ought to be able to replace the whole class with something like \S*

1:39 joegallo: Mmmm... I have commit that fixes that stuff.

1:39 I think.

1:39 Pushed.

1:40 amalloy: i was referring to line 163 (169 after your push)

1:40 the \\ can go away as it's meaningless here, or you can (probably, untested) replace the whole [...] with \S

1:41 joegallo: Oh, gotcha, I'm not in that stuff at the moment, but maybe technomancy is. I've messed with font lock stuff before, and I know it's way too late for me to hope to get it right.

1:41 So I'm going to leave that alone. ;)

1:42 amalloy: joegallo: sure. i haven't messed with emacs at all, but i have a pretty strong regex background

1:42 clojurebot: emacs is best configured for Clojure with instructions at http://technomancy.us/126

1:43 amalloy: clojurebot: thanks, but who asked you?

1:43 clojurebot: Titim gan éirí ort.

1:51 seangrove: Hey all, I can't seem to get lein swank to work properly

1:51 Whenever I evaluate my (ns statement, it trips up

1:52 I realize that's vague, but I'm not really sure where to look

1:55 amalloy: same code work copy/pasted in lein repl?

1:59 seangrove: ^, and also how are you loading the code into slime? C-c C-k is how i usually start

2:06 seangrove: amalloy: C-x C-e on the (ns statement

2:06 C-c C-k would be smarter

2:07 amalloy: seangrove: if i don't start with a C-c C-k things mysteriously break. C-x C-e works better after that, usually

2:08 seangrove: amalloy: That looks much better, thank you

2:08 bhenry: when doing C-x C-e down the file, you'll often forget one of your forms and that's why things will break.

2:08 i use C-x C-l and load the whole thing at once.

2:11 amalloy: bhenry: C-c C-k does that too

2:12 bhenry: C-c C-k compiles. loads it after?

2:13 technomancy: load/compile is a distinction slime inherits from common lisp

2:13 it has no meaning in clojure

2:13 amalloy: that's what i thought

2:14 bhenry: oooh cool. well i should start using C-c C-k then so i don't have to push enter after.

2:26 seangrove: Hmm, seems like compojure doesn't have serve-file anymore...

2:26 clojurebot: compojure is http://github.com/weavejester/compojure/tree/master

2:28 amalloy: clojurebot: why are you suddenly volunteering information nobody wants today?

2:28 clojurebot: what should I do today, it is the weekend and all

3:32 joegallo: Pushed durendal again, pretty much finished the sort-ns stuff, except for the crazy-fun ns example that bhenry sent.

3:32 And I'm going to sleep. Goodnight, clojure!

3:39 jjido: (fn) does not take doc?

3:44 amalloy: it's an anonymous function. how would you get at the doc for it?

3:45 jjido: In my case it is a struct function

3:47 the function is saved in a structure

3:48 amalloy: you can do something like (def x (with-meta (fn [a] a) {:doc "test"}))

3:49 jjido: ok

3:49 amalloy: that's not perfect though

3:49 ie, (doc x) won't work. but at least you can see the docs with (:doc (meta myfn))

3:55 jjido: defn is a macro isn't it? What does it do for the doc?

3:58 amalloy: i've been looking

3:59 can't really tell. try macroexpanding it; it looks like the docstring vanishes

4:00 or i guess it...tacks the metadata onto the name at macroexpansion time, so that once it's expanded the string is hidding inside of (meta myfunc) already

4:02 jjido: ,(defn myfunc "myfunc doc" [] 1) (meta myfunc)

4:02 clojurebot: DENIED

4:02 jjido: anyway it is not in (meta myfunc)

4:07 flintf_: Hey, does anyone happen to know if someone has translated the SICP examples to Clojure?

4:08 it's not hard to look at them and "imagine" them into Clojure, but it'd be nice if someone had already done to work

4:09 hah, actually...apparently there's a whole website devoted to the idea...nvm

4:35 coldhead: so it turns out its a bad idea to evaluate (iterate inc 0) at the repl

4:35 i learned this the hard way

4:39 fliebel: morning

4:40 seangrove: ,({:a "34"} {:b 3241})

4:40 clojurebot: nil

4:40 jjido: seangrove: {...} is a function

4:41 seangrove: Trying to merge those two maps

4:41 ,(merge {:a "34"} {:b 3241})

4:41 clojurebot: {:b 3241, :a "34"}

4:41 seangrove: Yup, that did it

4:41 Not sure what I did differently

4:42 jkkramer: coldhead: (set! *print-length* 103)

4:42 seangrove: ,(merge (for [key (keys {:a "34" :b 3241})] {key (key {:a "34" :b 3241})}))

4:42 clojurebot: ({:a "34"} {:b 3241})

4:42 seangrove: ,(for [key (keys {:a "34" :b 3241})] {key (key {:a "34" :b 3241})})

4:42 clojurebot: ({:a "34"} {:b 3241})

4:42 seangrove: Weird :P

4:43 coldhead: thanks jkkramer

4:45 amalloy: seangrove: why is that weird? you're taking each key from the map, and inserting it into the new map with whatever value it had in the old one

4:47 ,(zipmap ((juxt vals keys) {:a 34 :b 3241}))

4:47 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (1) passed to: core$zipmap

4:47 amalloy: ,(apply zipmap ((juxt vals keys) {:a 34 :b 3241}))

4:47 clojurebot: {3241 :b, 34 :a}

4:47 amalloy: seangrove: ^^ this one's more fun

4:50 seangrove: Haha

4:50 But why are they two separate maps instead of one, even with the merge?

4:51 amalloy: oh, i see. sorry, missed that

4:51 ,(into {} (for [key (keys {:a "34" :b 3241})] {key (key {:a "34" :b 3241})}))

4:51 clojurebot: {:a "34", :b 3241}

4:52 amalloy: seangrove: tada!

4:52 tomoj: you would've needed to apply the merge

4:52 seangrove: Haha

4:52 Nice :)

4:52 amalloy: it's amazing the things that suddenly turn easy when i remember that juxt exists

4:53 it's like map, but rotated ninety degrees

4:58 seangrove: What would be the equivalent of scheme's member? in clojure?

4:59 (member? 'a '(a b c d)) => #t

4:59 Chousuke: you can use the java .contains method I think

4:59 ,(.contains '(a b c d) 'a)

4:59 clojurebot: true

4:59 seangrove: Oh, nice

5:00 Chousuke: it doesn't exist as a clojure function because it's slow :)

5:01 seangrove: Thanks :)

5:04 amalloy: ,(some #('a) '(a b c d))

5:04 clojurebot: java.lang.IllegalArgumentException: Wrong number of args (1) passed to: sandbox$eval7126$fn

5:05 amalloy: ,(some #{'a} '(a b c d))

5:05 clojurebot: a

5:05 amalloy: ,(some #{'a} '(b c d))

5:05 clojurebot: nil

5:05 amalloy: seangrove: ^^

5:11 here i'm using the singleton set a as a predicate. but (some) takes any predicate, eg

5:11 ,(some even? [1 7 4 9 8])

5:11 clojurebot: true

5:25 amalloy: to go along with some there are also every? and not-any? not-any seems kinda silly to me - isn't it just (complement some)?

5:26 but anyway, way past bedtime to me. have a good weekend, folks

5:27 ,(source not-any?)

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

5:27 amalloy: anyway not-any is written as (comp not some), fyi

7:40 fliebel: What do you guys usually do for static files in a Ring app? I tried Ring's wrap-file, which is not very configurable and even considers index.img123.jpg an index file. Then I tried using Jetty directly using :cofigurator, which gave me a 403 on the web root.

8:37 Bahman: Hi all!

8:37 neotyk: Morning Bahman

8:38 Bahman: Morning neotyk.

8:42 fliebel: neotyk: You posted the uncle bob video the other day, right? Where you by any chance at the Amsterdam Clojurians the week before?

8:43 neotyk: fliebel: Hi, I'm here every meetup, we host it

8:44 fliebel: neotyk: I'm Pepijn, I was there as well. :) I think someone must have mentioned your IRC name there.

8:45 neotyk: fliebel: Hubert here, I go by that nick everywhere

9:15 notsonerdysunny: Hello everybody, I am not sure if the question really belongs here .. but I am asking since it is part of clojure-contrib... http://clojuredocs.org/v/436 what exactly are self-recursive-sets?

9:27 fliebel: Is there something like filter that splits the result into 2 seqs based on pred?

9:28 rhickey: ,(doc split-with)

9:28 clojurebot: "([pred coll]); Returns a vector of [(take-while pred coll) (drop-while pred coll)]"

9:30 fliebel: rhickey: Sorry, I mean… put all the ones that qualify in one seq and the others in the other. But the relation is the same as take-while => split-with, only with filter.

9:30 rhickey: ah

9:31 fliebel: So I could use not= for the one and = for the other, but I was just wondering if it exists.

9:33 The clojure.core ns is really shallow and wide if you ask me, not easy to find things. Much better the way contrib/java/python are structured.

9:33 rhickey: fliebel: not sure there's anything better than filter and remove for that

9:33 fliebel: rhickey: Thanks :) I'll use them.

9:34 neotyk: rhickey: Hi, do you think this could make to c.core? http://groups.google.com/group/clojure-dev/browse_thread/thread/bbf34a823f3081d6#

9:35 MayDaniel_: fliebel: clojure.contrib.seq-utils/separate?

9:36 fliebel: MayDaniel_: Yay!

9:36 rhickey: neotyk: not with that implementation

9:37 neotyk: rhickey: I would also like to post a ticket with patch to assemba http://groups.google.com/group/clojure-dev/browse_thread/thread/cb6c2a9fe9b20b55#

9:37 rhickey: neotyk: have you sent in a CA?

9:37 neotyk: rhickey: there have been few commits after that, but how do I make it nice so it could come to core?

9:37 rhickey: yes

9:38 rhickey: neotyk: Ok, I see you in the list

9:41 neotyk: rhickey: thanks

9:41 rhickey: neotyk: you can't use metadata for that. Also, this is something that has been asked for for futures and delays, so a common API would make sense. Unfortunately, it doesn't make sense for all refs, so needs some care in design

9:42 fliebel: split-with is lazy, right? I'm splitting a line-seq with it, and returning the parts in a lazy-cat, so the first can be accessed without reading adn parsing the second part.

9:42 neotyk: rhickey: why metadata is no go for it?

9:43 rhickey: neotyk: that kind of use of metadata is a hack

9:44 neotyk: ok

9:45 I will try to find more info about futures and delays in context of check ability

10:19 fliebel: Can someone explain me briefly how classloaders work in Clojure? I'm loading files form the classpath by using the class of an fn in the same dir, but I'm havin circular imports now. When I use a local fn, I'm somehow unable to find the file. What to do?

10:36 What is the difference between DynamicClassLoader and AppClassLoader? The one half of my app seems to be loaded with the one, while the other half uses the other.

10:37 This prevents parts of my app of getting resources from the cp.

10:48 Well, turns out I can use the dynamic one myself directly to solve the problem. Got to run now. Later

11:04 slyrus: if anyone's interested in fnparse (or cheminformatics for that matter) I've started blogging my experiences with using fnparse for parsing SMILES strings: http://slyrus.github.com/2010/09/17/parsing-smiles-with-fnparse.html

11:06 Bahman: What's the URL for build.clojure.org index file (maven)?

11:08 Good news...clojure.org is now accessible here with no need to proxy software.

12:05 jonasen: ,(keyword "")

12:05 clojurebot: :

12:05 jonasen: ^^ is that ok behaviour?

12:07 notsonerdysunny: ->(keyword "")

12:07 sexpbot: ⟹ :

12:07 notsonerdysunny: ,(keyword "")

12:07 clojurebot: notsonerdysunny: No entiendo

12:08 leafw_: is there such thing as a cumulative map?

12:08 mrBliss: there is a cumulative reduce called reductions

12:09 leafw_: I'v ebeen using cumulative map logic for a qwhile now. If the map itself was cummulative, it would be easier...

12:09 aha

12:09 ,(doc reductions)

12:09 clojurebot: "([f coll] [f init coll]); Returns a lazy seq of the intermediate values of the reduction (as per reduce) of coll by f, starting with init."

12:09 leafw_: that is not clear to me--what does it mean?

12:09 Chousuke: jonasen: no, but it's currently considered an user error

12:09 a*

12:10 mrBliss: ,(reductions + (range 1 10))

12:10 clojurebot: (1 3 6 10 15 21 28 36 45)

12:10 leafw_: I see

12:10 but applied to a list of k/v pairs, where some keys are duplicated, will not concat the corresponding vs

12:11 mrBliss: leafw_: what exactly are you trying to do?

12:11 jonasen: Chousuke: ok, thanks

12:12 leafw_: I'd like a map that, when assoc, it adds the element wrapped in a set. If the key is already there, conj to that set.

12:12 mrBliss: ,(merge-with conj {:a 1, :b 2} {:a 3})

12:12 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IPersistentCollection

12:12 mrBliss: ,(merge-with conj {:a [1], :b [2]} {:a [3]})

12:12 clojurebot: {:a [1 [3]], :b [2]}

12:13 leafw_: cool!

12:13 mrBliss: still not right ^^ but you get the point

12:13 leafw_: merge-with may work :)

12:16 just reduced 4 lines of code to "apply merge-with union"

12:16 fantastic :)

12:23 the beauty of chosing the right functions is that the code gets shorter, clearer to read, more explicit as to what it does, and has less points where errors can sneak in. Ah, clojure!

12:44 any advice on debugging monads?

12:45 I find the stack trace doesn't show much, points to the "domonad" line and not within the domonad declaration.

12:56 sproust: Is there a non-lazy version of map? or should I use (doall (map ...) )

12:56 leafw_: doall

12:57 raek: or dorur

12:57 *dorun

12:57 sproust: Thx.

12:57 leafw_: ,(doc dorun)

12:57 clojurebot: "([coll] [n coll]); When lazy sequences are produced via functions that have side effects, any effects other than those needed to produce the first element in the seq do not occur until the seq is consumed. dorun can be used to force any effects. Walks through the successive nexts of the seq, does not retain the head and returns nil."

12:57 raek: ,(doc doseq)

12:57 clojurebot: "([seq-exprs & body]); Repeatedly executes body (presumably for side-effects) with bindings and filtering as provided by \"for\". Does not retain the head of the sequence. Returns nil."

12:57 raek: I most often use doseq in that case

12:57 sproust: I actually need map, but I assign my result to a thread-local binding, so I need to force it.

12:58 raek: ah, then doall looks like the right thing

12:58 sproust: It's one of those recursive parsers that accumulates state; better modeled with some state that gets appended to.

12:58 Learning more and more about clojure, it seems like there should be a convention for lazy vs. non-lazy variants, e.g. map and map*

12:59 Python has the same problem, map vs. imap

12:59 leafw_: sproust: assume all is lazy

12:59 sproust: I know, but the non-lazy variants do exist.

12:59 Well, some of tehm.

12:59 Also, a similar situation occurs with application, some functions that take a sequence, and some that take varargs, which are otherwise identical.

13:00 Vinzent: hi. how can I create regexp from string var?

13:01 sproust: re-pattern

13:01 ,(re-pattern "(.*)")

13:01 clojurebot: #"(.*)"

13:01 sproust: ,(re-pattern (format "%%%ds" 2))

13:01 clojurebot: #"%2s"

13:03 Vinzent: Thank you!

13:07 leafw_: what is the best way to filter a map? I.e. remove some entries, but returning a map? filter returns a sequence that needs (into {} (filter ...))

13:09 ohpauleez: leafw_: As far as debugging domonad...

13:09 You can just macroexpand it

13:09 which may make things a little clearer

13:10 leafw_: ohpauleez: not when there is too much recursion--been there

13:10 hum. I could execute the macroexpanded version

13:10 ohpauleez: right

13:10 leafw_: thanks

13:11 ohpauleez: np, see if it helps, and I'll ping you if I think of something else

13:15 raek: leafw_: (into {} (filter (fn [[k v]] ...) m)) ; one way of doing it

13:16 leafw_: raek: that's how I do it. I was wondering if there is an easier way, like a filter-map or so

13:16 raek: or, you can use dissoc, if you know which keys you want to remove in advance

13:16 Raynes: raek: What arrow did you use for trattern?

13:17 raek: Raynes: "U+21D2 RIGHTWARDS DOUBLE ARROW"

13:18 and "U+21CF RIGHTWARDS DOUBLE ARROW WITH STROKE" for exceptions

13:18 Raynes: Hrm. Never saw that onew.

13:18 one*

13:19 raek: it's in the Arrows unicode block

13:19 leafw_: raek: no, the fn must peek into the value

13:19 it's ok, it's not terrible

15:17 alpheus: Halfway through _The Joy of Clojure_, and the book really is teaching me new ways to think about programming. I liked the other two I read first, but I'm kind of glad I saved this one for last.

15:19 (the other two Clojure books, if that wasn't clear)

15:33 nex: how can I make a struct passing the keys in a list?

15:33 mrBliss: (apply (partial struct struct-name) [key1 key2...]) is what I do

15:33 amalloy: struct-map, or apply, depending what you mean

15:37 nex: well im parsing a csv, and i want to make a struct-map of all the rows, i have each row in a '( ) and wanted to pass those lists directly to make each of the structs in the struct-map

15:38 (im testing apply, thank you guys very much)

15:38 LauJensen: nex: perhaps you should check out clojure-csv on github, its quite good

15:48 chouser: LauJensen: PM, in case you missed it.

16:09 arohner: ,(let [a|b 42] (println a|b))

16:09 clojurebot: 42

16:09 arohner: is | (pipe) guaranteed to be valid character in symbols?

16:09 similarly for &

16:10 chouser: I don't think so.

16:10 amalloy: i think & is, at least, isn't it?

16:10 mrBliss: I quote: "Symbols begin with a non-numeric character and can contain alphanumeric characters and *, +, !, -, _, and ? (other characters will be allowed eventually)"

16:11 I could be that & and | will be used for something else later

16:11 hiredman: that list doesn't include < and >, which are used in clojure.core

16:12 < > also look great in Mensch

16:12 mrBliss: hiredman: I copied it from http://clojure.org/reader#The%20Reader--Reader%20forms

16:12 hiredman: I am well aware where it is from

16:13 mrBliss: the docs should be updated then

16:14 arohner: I'm doing a lot of bayesian statistics, so it'd be nice to write P-a|b. it'd be nice if I could do P(x,y), but I'll settle for P-x&y

16:15 hiredman: P′xy

16:15 LauJensen: arohner: if it ever changes you can fix your code with sed

16:15 arohner: LauJensen: true

16:18 hiredman: ,(let [x 1 x′ (inc x)] x′)

16:18 clojurebot: 2

16:19 amalloy: it's my understanding that collections do fast equality checks by computing their hash at construction time, but i can't find where this is happening in the source. can anyone point me in the right direction?

16:21 hiredman: amalloy: I don't think they do it at construction time, they calculate it if asked and then cache it

16:22 but I've never looked

16:24 arohner: amalloy: search for "hashCode" in the java source

16:24 hiredman is right, it's lazy & cached

16:27 amalloy: hiredman: thanks, i see they're caching the hashcodes now. but where are they getting used? it looks like the equiv/equals methods in eg ASeq and PersistentList just iterate over their elements every time

16:28 LauJensen: yea I dont recall seeing equiv check the hash, just size, type and then elements

16:29 amalloy: oh duh. cause seqs can be infinite, so hash would never finish

16:30 arohner: amalloy: yeah, but = on two infinite seqs would never finish either

16:30 interesting. That means you can't use an infinite list as a key in a map

16:31 amalloy: arohner: but (= (range) []) can finish, which it couldn't if you hashed (range) first

16:31 arohner: amalloy: good point

16:31 note to self. Don't try (.size (range))

16:32 amalloy: ,(let [x (range) m {x 10}] (m x))

16:32 clojurebot: Execution Timed Out

16:32 amalloy: aww, really? i thought it could use identical?

16:32 arohner: amalloy: maps use hash codes

16:33 sets too

16:33 LauJensen: ,({(range) 5} (range))

16:33 amalloy: yeah, i guess they would have to

16:33 LauJensen: -> ({(range) 5} (range))

16:33 clojurebot: Execution Timed Out

16:33 sexpbot: Execution Timed Out!

16:34 amalloy: ,(= (range) [])

16:34 clojurebot: false

16:34 amalloy: whew. would hate to be wrong about that too

16:35 hiredman: in that case you can just do a type check to shirt circuit equality

16:35 although vectors and lists can be equal to each other

16:35 lists are seqs but seqs are not lists

16:36 and range produces a seq

16:37 amalloy: yeah, the type check can't be allowed there

16:37 ,(= (range 0 1) [0])

16:37 clojurebot: true

16:38 LauJensen: but am I correct in stating that the above check will fail in the master branch now?

16:40 amalloy: LauJensen: i don't know, but i hope not. i thought seqable objects with the same contents were supposed to compare as equal

16:40 LauJensen: I think the equiv branch changed that

16:41 Raynes: Heh. Ran out of heap space.

16:45 LauJensen: Raynes: The bot died?

16:45 Raynes: LauJensen: I have some pretty tight JVM options in place that I've been trying out. This is the first time I've ever run out of heap space with them. :p

16:46 hiredman: amalloy: that is not true

16:46 sequable objects with the same contents do not compare as equal

16:46 ,(= (seq {:a :b}) {:a :b})

16:46 clojurebot: false

16:47 amalloy: hiredman: good point

16:47 arohner: ,(= [1 2 3] (list 1 2 3))

16:47 clojurebot: true

16:48 arohner: ,(= {:a :b} {:a :b})

16:48 clojurebot: true

16:48 arohner: ,(class (seq {:a :b}))

16:48 clojurebot: clojure.lang.PersistentArrayMap$Seq

16:49 arohner: (= (array-map :a :b) (hash-map :a :b))

16:49 ,(= (array-map :a :b) (hash-map :a :b))

16:49 clojurebot: true

16:50 arohner: ,(= [1 2 3] #{1 2 3})

16:50 clojurebot: false

17:21 _Vi: "Function must be free of side effects because of it can be called multiple times". Does it mean Undefined Behaviour if it has them (for example, if it writes a log message to file) or it just warns you that your side effects may occur more than once?

17:23 dnolen: _Vi: the later

17:26 acts_as: Question: Are there any posts (or whatever) that talk about some interesting applications for Clojure? IE, cases where it solves a given problem exceedingly well? Or cases where it's less ideal? Sorry, that's a crappy question. I'm really liking Clojure, and I'm just wanting to absorb some opinions/blah before I really start digging in.

17:27 May or may not be the best way to learn a language, but they usually give me things that I look out for in the language

17:29 LauJensen: acts_as: I do a lot of different stuff with Clojure on my blog at bestinclass.dk

17:31 If you want an example of what Clojure does exceedlingly well, see the Scala Vs Clojure Concurrency post. If you want something its less ideal for, see the Fluid Dynamics post

17:41 arohner: man, I wish ints could hold metadata. I really want "typed ints"

17:42 I have two vectors of entirely different objects, and I typically look up values in the vectors. I'd really like to be able to put a type on the ints used to look up items in the vectors, so I don't accidentally use the wrong int to lookup in a vector

17:44 raek: something like SML's datatypes would be interesting. maybe this can be achieved with [:type-tag value] or records, though

17:44 amalloy_: arohner: why not just use a value,type pair of some kind? map, vector, whatever

17:45 arohner: amalloy_: I need to use vectors of primitives, for speed reasons

17:46 amalloy: metadata would slow things down too

17:47 you could hack something up, like use negative numbers for one of the vectors

17:47 then if you use the wrong int, you'll get an ArrayIndexOutOfBoundsException

17:47 arohner: amalloy: If we had real escape analysis, the metadata check could be an assert that can be compiled out

17:48 _Vi: Is there a table somewhere that shows similarities and differences between usual variable, ref, atom, agent and other such things (if any)?

17:49 arohner: _Vi: yes, there's a table. I don't remember where

17:49 amalloy: _Vi: i know there's one in the joy of clojure. might be one in labrepl, maybe?

17:49 _Vi: arohner, May be all (doc ...) pages about these function should link to it?

17:50 (Looking up what "labrepl" is)

17:56 http://stackoverflow.com/questions/1028318/clojure-mutable-storage-types "Disclaimer: All of this information is informal and potentially wrong. Do not use this post for gaining an understanding of how Clojure works." Is it really wrong somewhere?

17:58 arohner: _Vi: vars don't always contain a root binding

17:58 (def x) is legal

17:59 here, x doesn't contain a root binding

18:08 hrm. attempting to eval symbols containing the pipe character completely hoses SLIME

18:13 _Vi: What doc page for "atom" does not mention "deref", "swap!" and "compare-and-set!"?

18:16 Atom vs Ref vs Agent. "swap!" vs "alter" vs "send". Is there a mnemonic not to confuse them?

18:17 amalloy: atoms swap a value for another atomically; refs get altered in transactions; you send agents instructions

18:17 _Vi: ^^ best i can do

18:17 _Vi: But to an atom you also "send" a function.

18:18 kumarshantanu: does anyone know if Clojars push works now with Windows?

18:18 amalloy: try thinking of swap! like apply, with an implicit first argument. then you're not sending atoms functions, you're calling functions on them

18:35 arohner: ,(contains? #{Double/NaN} Double/NaN)

18:35 clojurebot: true

18:35 arohner: what's up with that?

18:37 acts_as: Ctrl+C seems to nuke cake. Is there a shortcut to tell cake to "stop that" sans the seppuku?

18:37 arohner: nevermind. on the equiv branch, that returns false

18:39 acts_as: oh wait, cake persists in some deity layer of my computer. blessed am i, for the preservation of my defn is eternal

18:39 _Vi: Have I understood atoms correctly? http://vi-server.org/vi/code/atoms.clj can print "Async" sometimes. Can somebody on SMP system try it?

18:45 arohner: _Vi: it's a bad idea to use emperical tests on concurrency

18:46 _Vi: arohner, How to really watch that asynchronousity? (BTW does that print "Async" for yours?)

18:47 arohner, (For me it doesn't print anything, but I have uniprocessor system that can't do real concurrency here).

18:47 arohner: _Vi: I'm pretty sure that won't print async

18:47 _Vi: why do you think it would?

18:48 _Vi: arohner, Because of main thread can see assignments to a1 and a2 in any order (not in order background thread swap!s them).

18:49 (if a1 and a2 are not close enough in memory to cache them and consider as one unit)

18:49 amalloy: _Vi: that code is not threadsafe. i don't understand how it's supposed to work

18:50 arohner: there's only one background thread. Those swaps happen 1) atomically and 2) deterministically

18:50 _Vi: amalloy, It is supposed to demonstrate that unsafety.

18:50 amalloy: as an aside, why (loop [] (let [stuff]))? (loop [stuff]) is equivalent

18:51 arohner: oh, nevermind

18:51 yes, you can read a1 and a2 out of order

18:52 but it's the reading that causes bugs here. If you replaced the atoms with refs, and then read inside a transaction, you wouldn't see async

18:52 _Vi: arohner, It swaps both a1 and a2. Unlike agents (as I understood from documentation), atoms are not safe when you use multiple of them and expect state-of-both-atoms-considered-as-the-whole consistent.

18:52 amalloy: _Vi: on my 4-core work computer it prints Async after about ten seconds

18:52 arohner: _Vi: right. I didn't pay attention to the reads

18:53 _Vi: arohner, Yes, when I see "async" messages I want to change atoms to 1. agents, 2. refs and see that it fixes things.

18:53 arohner: you should see async on agents as well, for the same reason

18:53 amalloy: _Vi: no, atoms are fine for this task, if you use them differently

18:54 _Vi: amalloy, OK. It works for you. ("works" means demonstrates pitfall of naive using atoms on concrete example).

18:54 amalloy: (def a (atom [0 0])) (future (swap! a #(map inc %)) (recur))

18:55 _Vi: arohner, On agents? Why? Documentation says that agents are synchronised.

18:55 amalloy: gives you an atom of two integers, increasing forever, and always the same

18:55 arohner: _Vi: where do you see that? Agent values are updated from a threadpool

18:55 _Vi: amalloy, Of course "(swap! a #(map inc %))" will work, as there is only one atom.

18:56 amalloy_away: yes. i'm just saying, switching to refs is often overkill; just use your atoms properly to fix the async issues

18:56 arohner: ,(doc send)

18:56 clojurebot: "([a f & args]); Dispatch an action to an agent. Returns the agent immediately. Subsequently, in a thread from a thread pool, the state of the agent will be set to the value of: (apply action-fn state-of-agent args)"

18:57 arohner: _Vi: in your example replacing atoms for agents, you still have the unsynchronized read problem

18:57 _Vi: arohner, (Thinking about difference between agents and atoms then)

18:58 amalloy_away: arohner is right. the writes are syncronous, but the reads are no more guaranteed than atoms

18:58 arohner: using agents, the writes aren't synchronus

18:59 _Vi: amalloy_away, (thinking how an example that prints "async!" for agents, but stops doing it for atoms can look)

19:00 How the code that naively misuse agents might look? (where atoms are actually needed)

19:16 amalloy, Can you please run this: http://vi-server.org/vi/code/agents.clj Expected: "agent" should drop to 0 once, but "atom" should be 1 or 2 indefinitely.

19:17 arohner, Is it a good demo for agent vs atom difference?

19:17 amalloy: ,(let [a (agent 0)] (send a #(do (Thread/sleep 1000) inc %)) @a

19:17 clojurebot: EOF while reading

19:17 amalloy: ,(let [a (agent 0)] (send a #(do (Thread/sleep 1000) inc %)) @a)

19:17 clojurebot: java.lang.Exception: No such namespace: Thread

19:17 amalloy: clojurebot: whatever. _Vi: that will demonstrate misusing agents

19:17 clojurebot: amespaces are (more or less, Chouser) java packages. they look like foo.bar; and corresponde to a directory foo/ containg a file bar.clj in your classpath. the namespace declaration in bar.clj would like like (ns foo.bar). Do not try to use single segment namespaces. a single segment namespace is a namespace without a period in it

19:20 _Vi: amalloy, What's wrong with "(send a #(do (Thread/sleep 1000) inc %)) @a" If should print either 0 or 1.

19:20 *It should print

19:20 amalloy: yes, it should print either. expecting it to always print 1 would be a misuse of agents

19:21 _Vi: amalloy, Atom will also print either 0 or 1.

19:21 amalloy: bet you a dollar?

19:21 or maybe you're right

19:21 * amalloy changes his mind about betting

19:21 _Vi: amalloy, Because of "@a" is a read. And reads are not synchorinsed both for atoms and agents.

19:21 amalloy: right

19:22 _Vi: amalloy, Please run that code and report if it works. Works means "agent=0 atom=1".

19:22 amalloy, The code does the same thing for atom and agent, but they should diverge because of their "atomness" and "agentness".

19:23 amalloy: won't they just diverge because of read timing?

19:23 neither one seems to be getting to zero, btw

19:24 _Vi: amalloy, Try waiting a bit more. If neither will drop to 0 the more complex racy test is probably needed.

19:24 amalloy: and i don't see why they would. the agents are queueing up their actions and then using swap! internally just like the atoms are

19:24 arohner: _Vi: again, emperical tests of concurrency are not sound

19:24 _Vi: arohner, When they signal failure, they sound.

19:25 amalloy: arohner: they can't prove something is thread safe, but they can prove something isn't thread safe

19:25 _Vi: arohner, Like that test with reading.

19:25 arohner: _Vi: the agent should never hit 0, because the swaps are deterministic

19:25 err, the atom should never hit 0

19:25 _Vi: amalloy, "the agents are queueing up their actions and then using swap! internally just like the atoms are" So what's real difference?

19:27 arohner: _Vi: the agent executions happen in a threadpool, async

19:27 amalloy: the difference is when you call (send) it returns right away. (swap!) blocks until the write succeeds

19:27 _Vi: arohner, Yes. Atom is more synchronised than agent and should "win" this.

19:27 arohner: what does win mean?

19:27 _Vi: arohner, Means retain consistent value (1 or 2). 0 means that some function is called out-of-order and a signal of failure.

19:28 arohner, If that assignments are executed out-of-order for agent, it should drop to 0.

19:28 amalloy: _Vi: still no zeros. pretty sure there never will be

19:28 arohner: right. an agent has a queue of actions to dispatch

19:28 _Vi: amalloy, Why never be? Why is agent weaker than atom then?

19:28 amalloy: it's not. who said it was? they're just suited for different tasks

19:29 (do (send agent fn) (await agent)) is identical to (swap! atom fn)

19:30 agents give you the ability to keep doing other stuff while they work, without getting out of sync

19:30 arohner: amalloy: careful. agents actions are not deterministic when receiving actions from multiple threads

19:31 each agent has a queue of actions. Those actions will be executed *in the order received*, in a thread pool

19:31 amalloy: arohner: atoms are just as nondeterministic across threads

19:31 _Vi: (thinking of simplest example that would signal synchronisation failure because of misusing agent instead of atom)

19:32 amalloy: oh, but you mean that you can still get out of sync. yes, agents aren't magic

19:35 arohner: _Vi: you've read http://clojure.org/agents and http://clojure.org/atoms, right?

19:36 _Vi: Yes. (Doesn't mean I've understood completely them)

19:37 arohner: _Vi: reading the source also helps

19:37 anyways, I have to run. Hope you find your answers

19:38 _Vi: arohner, I think building an example that diverge only because of differences between agents and atoms can help even more.

19:44 amalloy: _Vi: the difference will be timing

19:47 _Vi: amalloy, Also I it is said that sending to a agent from a transaction will not be duplicated (unlike swapping! an atom).

19:48 amalloy: maybe so. i don't remember

19:48 _Vi: http://malloys.org/~akm/tmp.clj

19:54 _Vi: amalloy, Thanks for the example. So the most differences are on the "caller" side.

19:54 amalloy: yes. swap! blocks and send doesn't

19:56 _Vi: So, is it true that agents are more heavyweight than atoms and refs are more heavyweight that agents?

19:56 amalloy: probably. not really my area of interest so i dunno

19:57 raek: atoms could be seen as lightweight refs, at least

19:57 agents and refs are heavy in different ways, I guess

19:57 amalloy: raek: yeah, that's what i think too

20:01 raek: also, yes. sends within transactions are held until the transaction succeeds

20:01 this also holds for sends within agent functions

20:02 there is the release-pending-sends function for getting around this, if one need it

20:03 amalloy: _Vi: btw if you want to do more agent/atom comparisons i've modified the above link to be an easy template function

20:06 _Vi: "what who stall" What? Who?

20:07 amalloy: see the doseq

20:07 who/what get bound to ag/send and then at/swap!

20:08 _Vi: I know. Just occasional phrase in the source.

20:09 amalloy: heh, yeah, it does look kinda funny

20:09 _Vi: It is the same as before, but shorter.

20:09 amalloy: yes

20:09 no retyping stuff

20:09 so if you want to test some different behavior set just write it in once

20:09 anyway, off to do some errands

20:23 Raynes: ivey: ohai

20:23 ivey: Raynes: howdy

20:42 kutku: hello.

20:42 I am experienceing some problems when running code in closure:

20:42 error: java.io.FileNotFoundException: Could not locate examples/introduction__init.class or examples/introduction.clj on classpath: (NO_SOURCE_FILE:0)

20:42 what have I done wrong?

20:44 raek: kutku: how did you start clojure?

20:45 kutku: tried two ways:

20:45 java -cp '/usr/share/java/clojure.jar:/usr/share/java/clojure-contrib.jar' clojure.main

20:45 and :

20:45 export PATH=/home/admin/.cljr/bin:$PATH; cljr repl

20:45 raek: you need to have the example code on the classpath too

20:46 it is not a part of clojure

20:46 kutku: how do I do that?

20:46 amalloy: kutku: your command line could be shorter, too: PATH=/home/admin/.cljr/bin:$PATH cljr repl

20:47 kutku: oh ya that worked too :)

20:47 I am fairly new at this.im really just a web developer

20:48 amalloy: no worries. most of the unix tools (bash, emacs, etc) have so many features you'll never know them all

20:48 raek: java -cp '/usr/share/java/clojure.jar:/usr/share/java/clojure-contrib.jar:programming-clojure/' clojure.main

20:48 kutku: where programming-clojure/ is the directory containing the examples directory

20:48 kutku: stupid question: how can I know my programming-clojure examples dir? I can use locate "keyword" but what would be the keyword?

20:49 raek: kutku: have you downloaded the examples?

20:49 kutku: no

20:49 coldhead: ah

20:49 :)

20:49 raek: http://github.com/stuarthalloway/programming-clojure

20:49 kutku: i want to access the fib series

20:49 raek: it even comes with a start script

20:50 kutku: where should I look?

20:50 or should I get all the files?

20:51 raek: http://github.com/stuarthalloway/programming-clojure/raw/master/examples/introduction.clj

20:51 there's the file for examples.introduction

20:51 kutku: thanks !!

20:51 raek: kutku: are you following the book or hacking on your own?

20:52 kutku: both.

20:52 raek: kutku: you can add the examples to cljr's classpath with "cljr add-classpath path/to/programming-clojure/"

20:53 kutku: i did that

20:53 raek: then you will always have that available when you start clojure with cljr

20:53 kutku: can I do the same with contrib?

20:54 raek: I think contrib is included by default in cljr

20:54 kutku: im still getting the same error msg.

20:54 raek: have you downloaded all the files or just introduction.clj?

20:54 kutku: http://pastebin.com/5gWKuaUY

20:54 just introduction.clj

20:55 raek: ah, no. you don't add the clj file to the classpath. sorry for not explaining

20:55 kutku: sorry

20:55 it makes sense now

20:55 raek: the namespace is "example.introduction" so clojure will look for examples/introduction.clj on the classpath

20:55 kutku: I add the entire programming-clojure dir ofc

20:56 raek: usually, you don't have to do this kind of stuff manuall

20:56 kutku: then why am I doing it?

20:56 oh shit du e svensk ju!

20:56 hhe :)

20:57 raek: kutku: #clojure.se :-)

22:13 laurus: So I found that someone, vshender, has created a library called clojure-gnuplot: http://bitbucket.org/vshender/clojure-gnuplot

22:13 My question is, how hard would it be to create such a thing for Python with similar syntax, so that matplotlib graphs could be generated from within Clojure with a Clojure-like syntax?

22:16 technomancy: laurus: you mean an alternative output backend?

22:16 laurus: Yes I think so

22:16 The example I'm referring to is here: http://bitbucket.org/vshender/clojure-gnuplot/src/bcff38db8260/README

22:16 technomancy: I think that really depends a lot more on the differences between gnuplot and matplotlib than having anything to do with Clojure

22:17 laurus: Well, my question is, I don't know how the Python "should" look in Clojure :P

22:17 I mean, the gnuplot syntax translates somewhat naturally

22:18 And it only took him 86 lines to make it work

22:18 I've only read 4 and a half chapters of _Practical Clojure_ so I don't know enough Clojure yet to tell how hard this would be.

22:22 technomancy: if you're just generating trees then it should be pretty natural; depends on python syntax you need

22:22 laurus: technomancy, the problem is that matplotlib uses objects for its plotting

22:23 For example, http://matplotlib.sourceforge.net/examples/api/histogram_demo.html

22:23 So I have no idea how one would translate that to Clojure syntax

Logging service provided by n01se.net