#clojure log - Mar 06 2011

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

0:00 skelternet: the documentation to write and parse xml in clojure is easier to find than the reason not to, and how to dump your struct to a clojure file, and read it back in.

0:01 Sure the clojure docs are there, but I haven't found a blog or an article that says "no no, don't do that...do this! It's native!"

0:01 amalloy: skelternet: if your struct doesn't include foreign java objects, the latter is trivial and the former is not

0:02 but send an email to alan@malloys.org to remind me and i'll see if i can put together a blog post about it

0:02 TimMc: Oh, this is bloody brilliant.

0:02 amalloy: TimMc: the article, or something you've just done?

0:03 TimMc: The serialization support.

0:03 skelternet: ?

0:03 TimMc: skelternet: Let me gist something for you.

0:03 amalloy: i think he's referring to the extensibility of print-dup

0:04 skelternet: I'm so new, I don't think I could ref my own butt at this point.

0:04 However, I did manage to use enlive to rescue our database schema documentation from our wiki. 3500 column defs

0:04 amalloy: hah

0:05 skelternet: so, now is a good time for me to sharpen my saw.

0:05 (only 3500 of the columns were documented. we have >6000)

0:06 TimMc: amalloy: OK, less brilliant than I thought.

0:06 amalloy: lol

0:06 TimMc: gist it already

0:09 TimMc: https://gist.github.com/857048

0:10 skelternet: oops

0:10 amalloy: $google defrecord2

0:10 sexpbot: First out of 20 results is: david-mcneil/defrecord2 - GitHub

0:10 https://github.com/david-mcneil/defrecord2

0:10 amalloy: i believe that includes readable print-dups

0:10 TimMc: heh

0:14 Thanks, I'll think about using that.

0:14 skelternet: it seems long. but yeah, thank you!

0:15 TimMc: For now, though... bed. G'night!

0:32 waxrose: Howdy every one. :)

0:34 amalloy: hola waxrose

0:34 waxrose: amalloy, :D

1:49 Scriptor: man, not seeing pipes to separate stuff in the topic feels weird

1:50 amalloy: silly Scriptor, pipes are for combining stuff! find | grep

1:51 Scriptor: but...but...delimeters!

2:28 amalloy: heehee. i just wrote (str tok). reminds me of the bad old days in C

2:33 Derander: amalloy: I have never written a C program

2:34 amalloy: Derander: it's not a bad thing to be able to do

2:34 what are your other languages?

2:34 shachaf: amalloy: Hopefully not with the same meaning as in C? :-)

2:34 Derander: amalloy: the web languages

2:34 amalloy: javascript, php, ruby, clojure

2:34 I guess I know haskell

2:34 amalloy: Derander: the joke is that strtok is one of C's worst APIs

2:35 it's inherently un-thread-safe

2:35 shachaf: Clojure is a web language?

2:35 Derander: I know that string stuff in C is the cause of problems

2:35 scode_: no.

2:35 scode_: wrong person, sorry. shachaf

2:35 I just meant that I came into programming primarily through the web

2:35 amalloy: Derander: strtok is worse. iirc instead of returning something, it modifies a global variable to reflect what it wants to return

2:35 Derander: brilliant

2:36 amalloy: $google c strtok string.h

2:36 sexpbot: First out of 7770 results is: strtok - C++ Reference

2:36 shachaf: To be fair, there's strtok_r.

2:36 sexpbot: http://www.cplusplus.com/reference/clibrary/cstring/strtok/

2:36 amalloy: shachaf: sure sure

2:37 shachaf: amalloy: Is strtok *inherently* thread-unsafe?

2:38 Derander: amalloy: I guess I was being vaguely untruthful. C was the first language I "learned", but I was 6-7 at the time and it did not stick.

2:38 amalloy: shachaf: C string to truncate. The contents of this string are modified and broken into smaller strings (tokens). Alternativelly, a null pointer may be specified, in which case the function continues scanning where a previous successful call to the function ended.

2:39 so to get more than one token out of your string, you call it with NULL after the first time

2:39 shachaf: amalloy: Sure, but it could use a thread-local variable instead of a global variable pretty easily.

2:39 amalloy: that's fair, i suppose

2:39 you still have to add the _r semantics to be any good at all, of course

2:40 shachaf: Of course.

2:40 And even then it's a pretty suspicious function.

2:41 amalloy: whereas (str tok) is delightfully clear and simple: convert tok to a string :P

3:07 guys fnparse is pretty awesome

3:20 khaliG: hi, what's the idiomatic way of getting the filenames in a directory?

3:21 amalloy: khaliG: file-seq, i think

3:21 khaliG: amalloy, looks good, thank you

4:59 octe: ,(/ 10 3)

4:59 clojurebot: 10/3

5:04 clgv: ,(/ 30 9)

5:04 clojurebot: 10/3

5:04 clgv: just curious^^

5:19 bennylut: what functions can iterate over a map (as key-value pairs)?

5:20 clgv: e.g. map ;)

5:20 afaik a map is a seq of key-value pairs

5:20 bennylut: clgv, hmm.. didnt know it can be handled like that

5:21 the map function parameter just need to get 2 parameters (aka key+value)?

5:21 clgv: &(map #(println (str "key = " (key %) " val = " (val %))) {:bla 1 :blubb 2.0 :lala 10/3})

5:21 sexpbot: ⟹ (key = :bla val = 1key = :blubb val = 2.0nil key = :lala val = 10/3nil nil)

5:22 bennylut: clgv, thanks!\

5:22 clgv: &(dorun (map #(println (str "key = " (key %) " val = " (val %))) {:bla 1 :blubb 2.0 :lala 10/3}))

5:22 sexpbot: ⟹ key = :bla val = 1 key = :blubb val = 2.0 key = :lala val = 10/3 nil

5:22 clgv: oh sexpbot omits line-ends...

5:23 bennylut: clgv, its ok i get the picture :)

5:23 clgv: I thought so ;)

5:25 yo might consider using destructuring in the fn

5:25 &(dorun (map (fn [[k v]] (println (str "key = " k " val = " v))) {:bla 1 :blubb 2.0 :lala 10/3}))

5:25 sexpbot: ⟹ key = :bla val = 1 key = :blubb val = 2.0 key = :lala val = 10/3 nil

5:29 the-anome: hi

5:33 bennylut: clgv, thank again :)

8:35 TimMc: This is because C is a toy language originally intended for implementing an OS to so a guy could write a chess program.

8:35 Ack, sorry -- hadn't scrolled down.

8:37 bawr: That reminds me - if I name some of my functions like X<-Y, taking Y and returning X, will people hate me? ;)

8:38 This is probably due to some Hungarian Notation virus, really.

8:46 ttmrichter: TimMc: It wasn't a chess program. It was Space War, if memory serves.

8:47 TimMc: It wasn't Ken what's-his-face at Bell Labs, wanting to write a chess AI opponent on spare hardware?

8:47 That's what one of my profs told me.

8:49 ttmrichter: Nope. It was tragically far goofier than that.

8:49 A chess AI would have a bit of cachet.

8:50 Unix started life as a quick and dirty OS for a PDP-7 to run Space War.

8:50 C started as a portable assembler to move Unix to a PDP-11.

8:51 (I may have the name of the game wrong in retrospect -- it was Space something, but that something might be War or something else.)

8:57 Ah, here we are! Space Travel. http://people.fas.harvard.edu/~lib215/reference/history/spacetravel.html

9:01 TimMc: haha

9:19 pyr: TimMc: i got my pb right fixed it with a lazy-seq

10:27 TimMc: Makes sense.

10:48 Argh, I just hit C-x C-s to save a doc in another program -- emacs is eating my brain!

10:49 clgv: lol. that isnt exclusive to emacs. I did strg+s when I had the impulse to temporary save a comment I was posting in a wiki ;)

10:50 it gets really stupid if paranoia kicks in and you'll end up pressing strg+s multiple times without a change ;)

10:52 TimMc: strg?

10:52 clgv: oops. in english: ctrl ;)

10:52 TimMc: ah

10:53 clgv: lol the left one already has no caption anymore

10:53 TimMc: When I do that, the browser prompts me for a filename to save the page to. >_<

10:53 clgv: yeah. thats the problem ;)

10:54 TimMc: Wha makes it worse is that some pages (e.g. Google Docs) will capture and use the keystroke.

10:54 clgv: but if they save the data it's probably ok ;)

10:54 deleting it without backup would be a real killer feature ;)

10:57 TimMc: I've been thinking about making a website that violates as many user expectations as possible. I may use that idea. :-)

10:58 clgv: lol. send me the link on completion ;)

10:59 TimMc: It's just an idea I'm kicking around.

11:11 eckroth: macros that use macros are a bit challenging for me; specifically, if I have multiple namespaces that each have a unique macro, and each of these macros use some common macro, where do I put the common macro?

11:14 clgv: the question remains the same if you replace macro by function ;)

11:14 does it sound easier now?

11:15 I would place it in a namespace for itself that communicates its "common" notion

11:16 perhaps you have other common definitions then you could put the together

11:16 s/the/them/

11:16 sexpbot: <clgv> perhaps you have othemr common definitions themn you could put them togethemr

11:16 clgv: oops

11:17 eckroth: I've had confusing experiences in which I felt that the common macro wasn't found, that it had to be local (duplicated for each use); I'll run a few tests right now

11:18 clgv: that sounds strange.

11:24 eckroth: clgv: yeah, I can't reproduce the behavior on a simple test; I suppose you're right :)

11:24 clgv: I used macros across namespace boundaries ;)

11:29 dfan: What's the idiomatic way to construct a map with precomputed values? I did it 'by hand' with (apply hash-map (apply concat (for [n (range 0 100)] [n (f n)]))) but that seems suspiciously verbose

11:30 clgv: dfan: you could use map-cat instead

11:30 eckroth: (reduce (fn [m n] (assoc m n (f n))) {} (range 0 100)) ?

11:31 DespiteItAll: sounds like a job for map-indexed

11:31 dfan: clgv: mapcat, you mean? I don't see how that's relevant here

11:31 clgv: like: (apply hash-map (mapcat (fn [n] [n (f n)]) (range 0 100))

11:31 DespiteItAll: (map-indexed f (range 0 100))

11:32 but for the more general case, I use apply hash-map. I've had that catch mistakes that reduce/assoc wouldn't catch (duplicate keys)

11:33 dfan: Aha, OK, you're using mapcat to combine my (concat (for))

11:33 clgv: yes

11:33 DespiteItAll: oh, duh, map-indexed doesn't return a map, so you'd still need apply hash-map

11:34 clgv: yeah. and he doesnt the index-property in this case at all ;)

11:34 thats only usefull when you iterate over other "objects"

11:35 dfan: OK, thanks, it sounds like there's nothing ridculously shorter

11:35 clgv: not really, since you have to create that list

11:36 DespiteItAll: clgv: Yep, I smoke lots of crack.

11:36 At best I was thinking of zipmap, but really I'm not making any sense

11:36 clgv: you shouldn't - it effects health and sanity ;)

11:37 DespiteItAll: (zipmap (range 100) (map f (range 100)))

11:38 but that's not really any clearer

11:38 dfan: Yeah, although there I'm duplicating (range 100)

11:38 I can make a little helper function, I just thought that maybe said helper function already existed

11:39 DespiteItAll: This seems like a common enough case that there should be.

11:41 clgv: you think?

11:41 the most general is the hash-map with the list of key-val pairs

11:42 dfan: and I like zipmap best as the way to write that helper function - I didn't like using it at the top level because it forced me to duplicate the domain, but it's fine inside the function

11:42 clgv: (defn create-hash-map [f coll] ...) ?

11:43 dfan: Right, I now have (defn make-hash-map [f vals] (zipmap vals (map f vals)))

11:43 clgv: &(doc zipmap)

11:43 sexpbot: ⟹ "([keys vals]); Returns a map with the keys mapped to the corresponding vals."

11:44 DespiteItAll: dfan: I would put vals in a let, that way if it's a calculated list it won't be calculated twice

11:45 dfan: How would vals get calculated twice?

11:45 clgv: DespiteItAll: like his defn above it's also calculated only ones ;)

11:45 s/ones/once/

11:45 sexpbot: <clgv> DespiteItAll: like his defn above it's also calculated only once ;)

11:45 DespiteItAll: yeah, ok

11:46 dfan: Thanks all

11:50 ApeShot: So I've been reading about how to implement lazy sequence functions and noticed here

11:50 http://clojure.org/lazy

11:50 that recursive calls in a lazy-seq block are always proper recursions rather than "recur" forms.

11:51 Doesn't this somewhat limit the usefulness of lots of functions, like map and filter, which now, though lazy, can also blow the stack?

11:51 Or does lazy-seq somehow trampoline them?

11:51 stuartsierra: it's similar to trampolining

11:52 a lazy seq consists of lazy cons cells, ...

11:52 … which are pairs sort of like <fn to return first>, <fn to return rest>

11:53 ApeShot: Yes, as soon as a typed the question, I realized it was probably a de facto trampoline

11:53 Good to know, though

11:55 TimMc: ApeShot: Look at the source for LazySeq. You can see the trampolining code, it's pretty cool.

11:56 ApeShot: rad

11:56 Clojure is pretty slick

11:56 Will we get proper tail calls when the JVM supports them or are the contours of the language comfortable with explicit or trampolined self-recursion

11:56 TimMc: I believe this is it: https://github.com/richhickey/clojure/blob/master/src/jvm/clojure/lang/LazySeq.java#L42

11:57 clgv: yes it is

11:59 bawr: I vaguely remember that explicit tail calls were meant to stay the way they are.

12:00 ApeShot: I like the idea of tail calls being made explicit, but not the idea of being limited to self-tail-calls

12:01 Although I can't say I've had too many experiences where I really wanted to tail call somewhere else

12:02 It just seems like it would be nice to remove the limitation

12:03 clgv: I dont understand your case completely

12:03 is that other function calling the one with the tail call again?

12:04 for mutual recursion you can use trmpoline afaik

12:04 ApeShot: So recur simulates a tail call to the same call points as the context

12:04 self-recursion

12:04 clgv: self-recursion has to be the same function ;)

12:04 ApeShot: True tail calls clear the stack context before any tail call at all

12:04 in clojure, yes

12:04 you can't "recur" to somewhere else

12:04 Only to the current function

12:04 This is less general than full tail call optimization

12:05 clgv: I would say the "self" in self-recursion defines that it is the same function

12:05 ApeShot: clgv: obviously

12:05 clgv: so you cant call another function in a self-recursion ;)

12:05 ApeShot: clgv: I am wondering if there are plans to provide explicit or implicit tail calls when the JVM is more modernized

12:07 TimMc: The problem will be backwards compatibility of new programs.

12:08 ApeShot: I don't see how it would break backwards compat

12:09 If tail calls become implicit, then nothing will change semantically in the language

12:09 if you add explicit tail calls

12:09 TimMc: Well, say you write a program for JVM 1.8 or whatever, relyn on implicit TCO.

12:09 ApeShot: say with a (tail destination & args) form like "recur" then old programs should be fine

12:09 Oh, sure

12:09 That kind

12:09 TimMc: Then run it on 1.6.

12:09 ApeShot: New programs won't run on the old version

12:09 DespiteItAll: I think it should always be explicit

12:10 TimMc: DespiteItAll: +1 to that.

12:10 ApeShot: DespiteItAll: I sort of agree witht his

12:10 At least the compiler can bark at you if you accidentally don't call in a tail position

12:10 And I suppose it allows more optimization, probably

12:11 TimMc: I believe the discussion for *Java* 1.7 included a "become" alternative for "return".

12:12 THat would match up to a JVM TCO feature and allow compile-time checking.

12:12 DespiteItAll: interesting

12:12 pd: clj-http returns response headers as a map, but it seems that is inherently broken for responses that set multiple cookies, since you have 2+ "Set-Cookie" headers in the response

12:12 you can only ever get access to the last one

12:12 anyone know how ring deals with this?

12:13 TimMc: DespiteItAll: Or maybe, since become is not a reserved keyword yet, they could repurpose goto. :-P

12:13 pd: Ooof, that's irritating.

12:13 DespiteItAll: I would love to see a GOTO comeback

12:13 I want to see a bunch of OOPers using GOTO

12:14 clgv: doesnt like the semantic behind goto

12:15 TimMc: Hmm, I guess they do sometimes add keywords.

12:15 http://download.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html

12:16 They added enum in v1.5 and assert in v1.4.

12:18 clgv: uh. whats strictfp?

12:19 TimMc: Strict floating point.

12:19 Never used it myself.

12:20 It's for portability, apparently.

12:20 https://secure.wikimedia.org/wikipedia/en/wiki/Strictfp

12:22 clgv: ah ok. never heard of it before ;)

12:22 TimMc: I didn't know what it was *for* until I looked it up just now, even though I've known of the keyword for... about a decade. :-P

12:26 OK, some web pages are alleging that TCO is being worked on but isn't likely to land in v1.7, but has a good chance at v1.8.

12:30 pd: now i need to work with a modified clj-http, what's the most reasonable way to go about doing that when my project uses lein?

12:31 TimMc: pd: Is it a local modification, or did you find a public fork?

12:31 pd: local, i just cloned the repo and added in some cookie handling code.

12:35 TimMc: I think there's a way you can install a local project using lein.

12:36 See if "lein install" is what you want.

12:40 pd: TimMc: yeah that will work, ty

12:41 tho it feels like it's going to be tedious to edit, lein install clj-http, then update deps in my project, then hit the repl to see if it's working out, ... =)

12:42 TimMc: pd: Try writing some tests in your clj-http fork

12:42 pd: i have

12:45 TimMc: Maybe there's a way of asking for local deps.

12:45 You'll still have to lein clean && lein deps && lein test

14:13 pyr: hi

14:13 while sending a blocking function to an agent

14:13 (this specific function constructs a seq with lazy-seq)

14:14 await-for doesn't exhibit the correct behavior

14:14 in that it never returns

14:14 send and send-off to the agent makes no difference

14:15 do i have to agentify each call in the function being sent ?

14:16 bennylut: hi all, i want to define a new exception from within clojure using deftype - i want to be able to supply message to the this exception using the extended exception constractor - can it be done?

14:27 hi all, i want to define a new exception from within clojure using deftype - i want to be able to supply message to the this exception using the extended exception constractor - can it be done?

14:29 tomoj: Exception is a class, deftype implements interfaces/protocols

14:29 TimMc: bennylut: Clojure frowns on extending concrete classes, by the way.

14:31 tomoj: I think there are only two options if you insist: gen-class and proxy

14:31 TimMc: You can alway extend it in Java and use it in Clojure.

14:37 bennylut: More importantly, perhaps... why do you need another exception type?

15:07 khaliG: is filter a good way to search a vector?

15:08 paraseba: khaliG: not very good, since it returns another seq. filter is good to, well, filter the vector

15:08 khaliG: you may want to use some

15:08 (some #(= :yes %) [:no :yes :maybe])

15:09 khaliG: paraseba, ah good point, i glanced past that before but didn't realise it wasn't just a predicate like its company

15:11 paraseba: khaliG: a common idiom is to use sets as predicates with some, since sets are function of their values

15:11 (some #{1 2 3} some-seq)

15:12 khaliG: paraseba, understood

15:21 is .equals the right way to compare strings?

15:25 mduerksen: no, = is

15:25 paraseba: khaliG: you can use .equals, but its easier to use =

15:26 khaliG: that's nice and consistent

15:27 mduerksen: yes, i love that about clojure. comparison is generally very simple here, no need to worry about pointer-equivalence like in java and the like

15:28 paraseba: yes, comparison turns out very easy for clojure types, since everything is immutable

15:28 khaliG: but strings are immutable in java too

15:29 paraseba: they are java strings

15:30 khaliG: is this illegal ... (fn [{_ name __ value}] ...)

15:31 amalloy: khaliG: it's legal, but probably not what you meant

15:31 khaliG: "Unable to resolve symbol: value in this context"

15:31 hm lets see

15:32 the dashes are keywords which i dont care about -- and the other two are values which i do

15:32 eg, {:name "Bodyweight", :value "197"}

15:33 paraseba: khaliG: try {_ :name _ :value}

15:33 amalloy: &((fn [{:keys [name value]}] (str name " " value)) {:name "Bodyweight", :value "197"})

15:33 sexpbot: ⟹ "Bodyweight 197"

15:34 paraseba: khaliG: { name1 key1 name2 key2}

15:35 Chousuke: or use the :keys shortcut like amalloy did

15:35 if there are keys you don't care about, those don't matter anyway

15:35 amalloy: right, the above is shorthand for ##((fn [{name :name value :value}] (str name " " value)) {:name "Bodyweight", :value "197"})

15:35 sexpbot: ⟹ "Bodyweight 197"

15:40 amalloy: khaliG: satisfactory?

15:40 khaliG: yes, i just finished testing the defn and it works beautifully

15:40 many thanks

15:41 just one last question -- "12" to a number, should i use read-string, or (. Integer parseInt "12") like in Java

15:42 i'm thinking read-string is more robust since it doesn't care about the size of the number

15:42 but if efficient?

15:43 Chousuke: it uses the java parsers

15:49 TimMc: ,(read-string "१२३")

15:49 clojurebot: java.lang.RuntimeException: java.lang.NumberFormatException: Invalid number: १२३

15:50 TimMc: Fascinating. It knew the characters were numerals, but couldn't use them.

15:51 amalloy: TimMc: i get that a lot when people read my handwriting

15:59 khaliG: hm i could swear i saw a zip/unzip function somewhere.. :/

16:00 brehaut: khaliG: zipping lists?

16:00 if so, map and apply map is your friend

16:01 khaliG: brehaut, i want to go from [[x1 y1] [x2 y2]...] to [x1 x2 ..] and [y1 y2 ..]

16:01 TimMc: map vector

16:02 brehaut: ,(map vector [[:x1 :y2] [:y1 :y2]])

16:02 clojurebot: ([[:x1 :y2]] [[:y1 :y2]])

16:02 tomoj: need to apply it

16:02 brehaut: ah yeah

16:02 ,(apply map vector [[:x1 :y2] [:y1 :y2]])

16:02 clojurebot: ([:x1 :y1] [:y2 :y2])

16:03 brehaut: ,(apply map vector (apply map vector [[:x1 :y2] [:y1 :y2]]))

16:03 clojurebot: ([:x1 :y2] [:y1 :y2])

16:03 brehaut: things that are their own duals are cool

16:04 tomoj: is that just transpose?

16:04 brehaut: tomoj: yes

16:05 amac: ,(interleave [:x1 :y1] [:x2 :y2])

16:05 clojurebot: (:x1 :x2 :y1 :y2)

16:08 khaliG: apply map vector works, not to understand why?!

16:08 hm i think i get it, that's very cool

16:08 brehaut: khaliG: its pretty simple if you take the time

16:09 amac: you're mapping the first items in each input vec into an output vector, then the second...

16:09 brehaut: khaliG: you dont need specific zip and unzip functions in a language with varargs and apply semantics

16:10 TimMc: brehaut: But if you *do* have zip, you don't have to remember what "map vector" implies each time you read it.

16:10 amac: ,(map vector [1 2] [3 4])

16:10 clojurebot: ([1 3] [2 4])

16:10 amac: is the same as:

16:10 brehaut: TimMc: sure but id rather it was called transpose

16:10 amac: ,(vector [1] [3])

16:10 clojurebot: [[1] [3]]

16:10 TimMc: brehaut: Yeah, that is a better name.

16:10 amac: ,(vector 2 4)

16:10 clojurebot: [2 4]

16:11 amac: uhh, first one is wrong sry

16:11 tomoj: map is just zipWith with arbitrary arity?

16:12 * khaliG just wrote (let [[x y] (apply map vector ...] ..) and it worked. magic!

16:13 khaliG: but yes it would look clearer with an explicit function

16:13 i'm sure incanter has one, which is probably where i saw it, now that i think about it

16:14 TimMc: There is such a profusion of programming languages right now. Has this always been the case, and most languages just get forgotton?

16:15 (forgotten, even)

16:15 khaliG: nope i'm mistaken, it's not in incanter either

16:15 tomoj: I think naturally with absolutely more programmers there will be absolutely more languages

16:15 TimMc: heh

16:15 tomoj: the history of the distribution of survival time would be interesting though

16:15 TimMc: I was thinking of the availability of tools, but you raise an excellent point.

16:16 khaliG: i'm not even trying to write clojure concisely it's just coming out that way

16:17 brehaut: there are more runtime platforms to build languages on now too, and you can get away with a slow homebrew runtime for many tasks

16:22 tsdh: I want to write a function that either gets a Vertex (some Java object) + some other args, or a seq of Vertex + some other args. How can I dispatch between the two?

16:22 clojurebot: http://www.math.chalmers.se/~rjmh/Papers/whyfp.pdf

16:23 amalloy: tsdh: your specification is unclear. by the second case do you mean [v other other], or [v1 v2 v2] other other?

16:24 TimMc: tsdh: multimethod dispatching on first of args?

16:25 tsdh: amalloy: One would be (--> v1 :type 'foo) and the other (--> [v1 v2 v3] :type 'foo)

16:26 TimMc: You mean (fn [c & _] (class c))? But what's the class of a seq?

16:26 TimMc: :default :-P

16:26 ,(class (seq [1 2 3]))

16:26 clojurebot: clojure.lang.PersistentVector$ChunkedSeq

16:26 TimMc: Well, ISeq or something

16:26 Chousuke: don't rely on the classes

16:27 amac: seq is an interface

16:27 Chousuke: right. though you can call seq on more than just ISeqs

16:27 TimMc: hrm

16:27 Chousuke: I'd just check if the thing is a vertex and treat it as a seqable thing if it isn't.

16:27 TimMc: ,(doc parents)

16:27 clojurebot: "([tag] [h tag]); Returns the immediate parents of tag, either via a Java type inheritance relationship or a relationship established via derive. h must be a hierarchy obtained from make-hierarchy, i...

16:27 Chousuke: with an if

16:27 amac: collections have functions that coerce them into seqs, but their class remains the collection type

16:28 (type (seq "aoeu"))

16:28 ,(type (seq "aoeu"))

16:28 clojurebot: clojure.lang.StringSeq

16:28 amac: ,(type (seq [1 2 3]))

16:28 clojurebot: clojure.lang.PersistentVector$ChunkedSeq

16:28 TimMc: ,(parents (class (seq "a")))

16:28 clojurebot: #{clojure.lang.ASeq clojure.lang.IndexedSeq}

16:28 tsdh: Chousuke: Hm, well, yes. I think that's the simplest solution. :-)

16:30 amalloy: TimMc: parents is not what you want: ##(supers (class (seq "a")))

16:30 sexpbot: ⟹ #{clojure.lang.Sequential clojure.lang.IPersistentCollection java.lang.Object clojure.lang.Obj java.io.Serializable clojure.lang.IMeta clojure.lang.Counted java.lang.Iterable clojure.lang.IndexedSeq java.util.List clojure.lang.ASeq clojure.lang.IObj java.util.Collect... http://gist.github.com/857695

16:31 TimMc: ,(doc supers)

16:31 clojurebot: "([class]); Returns the immediate and indirect superclasses and interfaces of c, if any"

16:31 tsdh: Why do vectors not implement ISeq?

16:31 amac: they do

16:31 tsdh: ,(seq? [1 2 3])

16:31 clojurebot: false

16:31 amac: ,(seq? (seq [1 2 3]))

16:31 clojurebot: true

16:31 TimMc: tsdh: They aren't seqs, they're collections.

16:31 amac: they need to be coerced, but it happens automatically for seq functions

16:32 pyr: so there are still ways to make agents block even with await-for and send-off, right ?

16:32 lpetit: Hello guys. Something totally off topic: for counterclockwise, I'd like to host the eclipse update site (it's really just a bunch of files hosted on an http server) myself, so that I can get by some way the number of downloads, for each version, per day/month, etc.

16:32 And now the question : what to use ? awstats ? webalizer ? analog ? I will not do intensive usage, I do not want to specialize on log statistics. If you know the best fit for my usecase, thanks in advance for sharing your thoughts.

16:33 amac: most webservers record access logs, just parse the logs to get the activity.

16:34 ...not entirely sure I understand the problem scope though

16:35 lpetit: amac: yes I understand that. The problem scope is: I publish a new version of counterclockwise, say 0.2.0. It's a bunch of files, one of whose I can count downloads on to know how many installations of the plugin have been made.

16:36 technomancy: lpetit: I host downloads on github, and I can see it broken down by version, but not by time.

16:37 not too flexible, but definitely easy: https://github.com/technomancy/leiningen/downloads

16:38 amac: send github a patch to pull analytics by date, solve the problem for everybody :)

16:38 lpetit: technomancy: an Eclipse update site is a set of related files, one located in say /updatesite/site.xml, and the others in say /updatesite/plugins/ccw.jar , /updatesite/features/ccw_feature.jar . So there is an organization of files from /updatesite/ URI which is somehow expected by the Eclipse client

16:38 technomancy: ah, gotcha

16:39 lpetit: technomancy: yeah :-(. So I really need some kind of ftp-like http exposure

16:40 * amac doesn't use eclipse :(

16:41 lpetit: I hoped I would not have to dig into apache configuration files again, seems like I was wrong :-(

16:41 amac: last year I started using lighttpd instead of apache, my life is now better

16:41 seriously, break up with apache and never look back

16:41 lpetit: Unless I find some java webapp which would do this at the application level (serve as a proxy for the filesystem, and register logs for me). I think I can suffer the performance penalty.

16:42 brehaut: lpetit: that should be fairly straight forward to cook up with ring

16:42 amac: actually yeah

16:42 amalloy: good point

16:42 brehaut: lpetit: there is static serving middleware, and it would be trivial to wrap that in another middleware to do the counting

16:42 lpetit: brehaut: sure, it's just that I want to stay focused on my need.

16:42 amac: serve the files through the file middleware, and wrap it with a counter

16:43 Raynes: I never got a chance to breakup with apache. My first webserver was nginx.

16:43 lpetit: Now, if "all in all" it would cost me less time to play with ring, then yeah, that might be fun

16:43 amac: Raynes: I wouldn't wish an apache configuration on my worst enemy

16:43 lpetit: that's tempting, indeed :)

16:44 brehaut: lpetit: the ring end is the easy part, i think you'd probably spend more time faffing about getting it running on your server with apache and what not than actually developing it

16:44 lpetit: Apache configuration is like monkey patching, ask google, copy & adapt :-(

16:44 Raynes: amac: I wouldn't wish nginx documentation on the cleverest webserver newbie.

16:44 amac: hahaha

16:45 Raynes: There isn't much in the way of "what is a webserver and how do I make it serve web?" documentation on nginx that I could find.

16:46 amac: there isn't a massive amount of docs out there for lighttpd, but its an incredibly simple setup

16:46 brehaut: Raynes: a web server is an amorphous blob that consumes http requests, and does something undefined to produce a new http response.

16:46 lpetit: brehaut: it always seems easy when we're sufficiently far from the detail. But I'm pretty sure that if I'm going this road, sooner or later I'd want some stats based on day, then on geography, and sooner or later I'll wake up having reinventing half webalizer features, albeit with my proprietary log file format :-(

16:53 amalloy: pyr: seems so, yeah

16:54 pyr: amalloy: well then i don't get why this blocks forever for me

16:55 amalloy: &(let [a (agent 0)] (send-off a #(do (Thread/sleep 4000) (inc %))) (await-for 2000 a))

16:55 sexpbot: ⟹ false

16:55 pyr: yep

16:55 amalloy: &(time (let [a (agent 0)] (send-off a #(do (Thread/sleep 4000) (inc %))) (await-for 2000 a) @a))

16:55 sexpbot: ⟹ "Elapsed time: 2001.618224 msecs" 0

16:56 pyr: my func calls lazy-seq on itself

16:56 i wonder if that's the case

16:57 amalloy: pyr: then your agent is returning a lazy seq instantaneously and you're wasting a bunch of time derefing, probably

16:57 try wrapping the await and the deref with (time)

16:58 pyr: time ?

16:58 amalloy: well, the deref will always be instantaneous. so maybe (time (doall @a))

16:58 pyr: oh

16:58 true

16:59 lpetit: technomancy: you gave me an idea !

16:59 technomancy: from the docs of artifacts.xml in the eclipse.org website: "It is possible to change those rules to have a filter matching for a particular artifact and change the output to point to a specific location."

17:00 technomancy: so I can change the default filter rule, and have all my plugins and features locations resolve to https://github.com/downloads/laurentpetit/ccw/*.jar

17:00 yay !

17:01 * amalloy doesn't understand, but sounds good!

17:02 * lpetit isn't totally certain to understand either :)

17:02 lpetit: I need to find a way to automate this so that I don't have to change the file by hand for each delivery

17:04 Hmm

17:14 pyr: gaah

17:14 amac: has anyone ever tried to send bulkmail through a gmail account? will them deliver them? (about 300 messages)

17:14 pyr: it blocks with loop / recur too

17:14 amac: using a lib like this one: http://blog.8thlight.com/articles/2010/4/21/mmemail-my-first-clojure-open-source-contribution

17:15 pyr: so it seems that if you poll the network await gets tricked

17:18 amalloy: pyr: i am dubious. maybe if you gisted some actual code...

17:18 pyr: will do

17:22 http://pastie.org/1640882

17:23 there's two versions that return a message list

17:23 amqp-topic is a lazy-seq, amqp-topic2 a loop/recur, both block even when inside an agent

17:28 amalloy: hm. seems like it ought to work, because mq is accepting InterruptedException

17:30 as a side note though you're abusing agents here if you don't care about their value. just use future, future-done?, and future-cancel

17:31 TimMc: I believe ants.clj abuses agents the same way.

17:31 Were futures not available yet?

17:32 (I think it is a Clojure 1.1 vintage.)

17:32 pyr: ah, great

17:32 brehaut: TimMc: ants is pre 1.0

17:32 TimMc: brehaut: yikes!

17:32 pyr: when did future get in clojure ?

17:33 amalloy: &(-> future var meta :since)

17:33 sexpbot: ⟹ nil

17:33 amalloy: hm

17:33 &(meta #'future)

17:33 sexpbot: ⟹ {:macro true, :ns #<Namespace clojure.core>, :name future, :file "clojure/core.clj", :line 5407, :arglists ([& body]), :added "1.1", :doc "Takes a body of expressions and yields a future object that will\n invoke the body in another thread, and will cache the result... http://gist.github.com/857799

17:33 brehaut: &(-> future var meta :added

17:33 sexpbot: java.lang.Exception: EOF while reading

17:33 amac: &(source future)

17:33 sexpbot: java.lang.Exception: Unable to resolve symbol: source in this context

17:33 brehaut: &(-> future var meta :added)

17:33 sexpbot: ⟹ "1.1"

17:34 pyr: ok seems good

17:34 there's no reason why my stuff will work with futures but using the right constructs is good

17:34 TimMc: Oh hey, that uses java.util.concurrent.Future

17:34 raek: the executors framework of java has been available for clojure users all the time, though...

17:35 pyr: anything like awai-for for futures ?

17:35 raek: pyr: (.get ftr TimeUnit/SECONDS 10)

17:36 pyr: 'k makes sense

17:36 raek: pyr: I wrote a ppost about this: http://blog.raek.se/2011/01/24/executors-in-clojure/

17:36 pyr: much more sense than what i did

17:38 raek: agents is a reference primitive built on top of executors and does not replace executors

17:39 pyr: thanks a lot, your blog post is really thorough

17:39 and will be of great help

17:39 raek: it would be nice if there was some documentation for certain java classes from a clojure perspective

17:39 TimMc: I need to learn about Executors. I don't think it existed the last time I used Java threads.

17:40 amalloy: TimMc: 1.5, right?

17:44 TimMc: Most likely v1.4.

17:44 Or even v1.2.

17:45 amalloy: i meant that's when executors appeared

17:45 TimMc: Ah, OK. I have no idea.

17:45 I just learned it existed this week,

17:45 .

17:52 tomoj: pyr: I wonder if lamina may be relevant to your interests

17:59 amalloy: raek: looking at your bloggy thing now. "a units of work" is an arity mismatch

18:07 pyr: tomoj: i'll look it up

18:07 well future don't get me a free pass either :(

18:09 raek: amalloy: thanks for spotting that!

18:15 tomoj: pyr: e.g. in master (wait-for-result (task (Thread/sleep 1000) "foo") 900) throws a TimeoutException while (wait-for-result (task (Thread/sleep 1000) "foo") 1100) returns "foo"

18:16 task being a macro similar to future except that it returns a result channel

18:17 but lots of related stuff is brand new and unstable

18:17 :(

18:19 pyr: tomoj: if the underlying mechanism is the same than for agents and futures it might not work either

18:20 \o/

18:20 tomoj: the underlying mechanism is quite different, if I understand what you mean

18:21 pyr: ok, with futures and the lazy-seq version it would fail but with the loop/recur one i get a result

18:21 tomoj: task does use an executor, and by default (I think) the soloExecutor agents use for send-off (right?). but otherwise, totally different

18:22 pyr: tomoj: ok

18:23 tomoj: using lamina just for that timeout thing in particular, of course, would be silly

18:25 pyr: yeah the idea of it is really interesting

18:25 amalloy: tomoj: less silly than using incanter to get an (average) function, at least

18:28 pyr: tomoj: the siphon approach is really interesting yes

18:28 i'll look into it seriously

18:28 clojurebot: I don't understand.

18:29 pyr: well guys thanks for your help, time to catch some sleep

18:47 Nanakhiel: tomoj, my old friend

18:47 I love what you've done with your beard.

18:47 tomoj: you call this a beard?

18:48 Nanakhiel: tomoj, no idea, I'm just quoting this comedy group.

18:49 tomoj, how much beard do you have?

18:54 tomoj: not enough to call it that

20:05 preyalone: Clojure can't find my *.clj files to compile them unless I type (set! *compile-path* (str *compile-path* ":.")). Which config file could I put this in?

20:06 TimMc: preyalone: What are you using to compile?

20:06 amac: preyalone: do you use leiningen?

20:06 amalloy: preyalone: use a build tool like cake or leiningen instead of doing it by hand

20:06 preyalone: I just want to compile hello.clj. I'll use Leiningen for anything more complicated.

20:06 TimMc: (compile 'hello)

20:07 amac: leiningen isn't as painful as you think

20:07 amalloy: preyalone: i literally have no idea how to compile things without a build tool. it's easier to use one than not to

20:07 preyalone: OMG

20:07 amac: type 'lein new projectname' and it'll populate everything you need

20:08 preyalone: I don't want any more files or directories than hello.clj.

20:08 TimMc: preyalone: You know you don't have to compile Ahead-Of-Time to run Clojure code?

20:08 amac: modify you src/project/core.clj file to (println "hello world")

20:08 then lein run

20:08 preyalone: TimMC: I do to test how various command line arguments will be evaluated by interpreted vs compiled code.

20:08 Is there ~/.cljrc or something similar?

20:10 TimMc: preyalone: Leiningen is super-easy to install (local, only takes a minute, uses ~/.lein for caching). It's dead easy to use, and pretty standard. (Cake is similar from a basic usage perspective.)

20:10 amac: I think you need to add :gen-class to your ns, then run javac -cp clojure.jar hello.clj

20:10 * amac thinks

20:10 amac: ...never actually done it manually

20:10 preyalone: amac: What does :gen-class do?

20:11 TimMc: I did it manually maybe once so that I knew how, and then started using a build tool and never looked back.

20:11 amac: http://clojure.org/compilation

20:11 that should have some more details :)

20:11 preyalone: amac: Thanks man

20:12 amac: &(doc gen-class)

20:12 sexpbot: ⟹ "Macro ([& options]); When compiling, generates compiled bytecode for a class with the given package-qualified :name (which, as all names in these parameters, can be a string or symbol), and writes the .class file to the *compile-path* directory. When not compiling, ... http://gist.github.com/857934

20:15 preyalone: Side note: When is -main run?

20:15 Cause clj hello.clj doesn't run it.

20:16 amac: I know there's a resource in jars that specifies the name, I only know how to config it with leiningen but it can be specified manually

20:16 s/name/main

20:16 sexpbot: <amac> I know there's a resource in jars that specifies the main, I only know how to config it with leiningen but it can be specified manually

20:16 preyalone: amac: Adding :gen-class doesn't appear to do anything.

20:17 amalloy: amac: META-INF/MANIFEST.MF has a Main-Class key iirc

20:17 amac: amalloy: that sounds familiar

20:17 preyalone: -main is only run when the script is compiled ???

20:18 amalloy: preyalone: or when you call (-main) yourself. it's not that hard

20:19 preyalone: amalloy: Surprises like that slow me down.

20:19 amalloy: My goal is to get a behavior like Ruby's if __FILE__ == $0 main end

20:19 amalloy: preyalone: then take the advice of everyone in this channel and start using tools that hide those surprises from you

20:19 preyalone: amalloy: Those tools don't hide the main/-main surprise.

20:20 TimMc: preyalone: Yes they do!

20:20 You add :main to your project.clj and DONE.

20:20 preyalone: Those tools will not make my script run (main) when it's interpreted.

20:20 amac: cave to the peer pressure.

20:20 TimMc: preyalone: Load-file it in a REPL and call (-main)

20:20 amac: all the cool kids use leiningen.

20:20 preyalone: TimMC: You mean add :main to the namespace?

20:20 TimMc: No, to the Leiningen or Cake project.clj file.

20:21 Anyway, the distinction you want is compiled on the fly vs. AOT.

20:21 Clojure is never interpreted.

20:21 Build tools give you both.

20:22 preyalone: TimMc. Clojure interprets user commands. The fact that behind the scenes they are compiled to byte code is an arbitrary qualification.

20:22 TimMc: Sure, have it your way.

20:22 brehaut: TimMc: marginally correct ;) any JVM bytecodes may be interpreted during their lifetime but that is irrespective of JIT or AOT for the clojure compiler

20:23 amac: jit compiling still blows my mind

20:23 that is straight up magic

20:23 preyalone: What's that about adding :main to my file? I have a main function specified. Should I add something to my namespace declaration?

20:24 TimMc: preyalone: :main is not added to your program.

20:27 brehaut: preyalone: have you read and digested all of http://clojure.org/compilation ?

20:27 preyalone: brehaut: I'm reading it right now.

20:28 brehaut: The problem is *compile-path* does not have "." by default. When I add that, hello.clj compiles just fine.

20:29 brehaut: then do that?

20:29 preyalone: brehaut: Clojure has no trouble running hello.clj, it just can't find it when I (compile 'hello).

20:29 TimMc: There is no reason for *compile-path* to have "." in it by default.

20:30 brehaut: preyalone: personally i think doing it by hand is madness

20:31 amac: ,*compile-path*

20:31 clojurebot: nil

20:31 preyalone: brehaut: On the other hand, needing tools just to compile Hello World is madness.

20:31 amac: "classes"

20:31 brehaut: compiling hello world is madness

20:31 amac: there are step by step instructions for building hello world in that page I sent you

20:31 sans tools

20:32 brehaut: AOT Compiling that is

20:33 amac: also, "hello world" is what clojurebot was born for :)

20:33 dfan`: Embarrassing question: How do I convert a sequence of chars to a string?

20:33 preyalone: amac: Those instructions only work for the example Hello World that comes with Clojure, not the same file located on my Desktop.

20:34 amalloy: dfan`: ##(apply str [\a \b \c])

20:34 sexpbot: ⟹ "abc"

20:34 TimMc: ,(str (seq "foo"))

20:34 clojurebot: "(\\f \\o \\o)"

20:34 amac: (reduce str [\a \b \r])

20:34 TimMc: worth a try

20:34 preyalone: This is rich: (compile 'clojure.examples.hello) java.io.FileNotFoundException: Could not locate clojure/examples/hello__init.class or clojure/examples/hello.clj on classpath: (NO_SOURCE_FILE:0)

20:34 amalloy: or clojure.string/join, if you want anything fancier than plain concatenation

20:34 TimMc: No wait, it wasn't.

20:34 amac: ,(reduce str [\a \o \e \u])

20:34 clojurebot: "aoeu"

20:34 dfan`: What clojurebot said :)

20:34 brehaut: preyalone: is your file in the correct directory structure?

20:35 dfan`: amalloy: Thanks, perfect

20:35 preyalone: brehaut: hello.clj is in /Users/andrew/Desktop.

20:35 brehaut: preyalone: then no, its not. put it in clojure/examples/

20:36 preyalone: brehaut: That won't help. Did you see the above excerpt? My Clojure can't even compile the example scripts.

20:36 Could not locate clojure/examples/hello__init.class or clojure/examples/hello.clj on classpath: (NO_SOURCE_FILE:0)

20:36 amalloy: preyalone: good idae. ask for help, then reject it instead of trying it

20:36 brehaut: preyalone: to quote the error you are vomiting at me "clojure/examples/hello.clj on classpath: "

20:37 if you dont put your file where its _explicitly tell you it should be_ it wont work

20:37 preyalone: all: MacPorts Clojure is having trouble finding ANYTHING, including the example scripts. Inserting my code there will not help me.

20:37 TimMc: preyalone: Why don't you try it, hm?

20:38 preyalone: THIS: (compile 'clojure.examples.hello) FAILS on my system.

20:38 brehaut: i let lein manage my project dependancies such as clojure, rather than some random package manager

20:38 amac: ,(time (apply str [\a\o\e\u]))

20:38 clojurebot: "Elapsed time: 0.128 msecs"

20:38 "aoeu"

20:38 preyalone: Straight from the Clojure - compilation tutorial: http://pastebin.com/raw.php?i=7StS2qvW

20:38 amac: ,(time (reduce str [\a\o\e\u]))

20:38 clojurebot: "Elapsed time: 0.15 msecs"

20:38 "aoeu"

20:39 amac: amalloy: damn, you win.

20:39 * amalloy declares himself the winnerrrr

20:39 preyalone: brehaut: That might help.

20:39 amalloy: amac: it's because str uses a StringBuilder internally

20:39 TimMc: Good to know.

20:39 amalloy: if it has to return a real String after every concatenation it can't do that optimization

20:39 clojurebot: It's greek to me.

20:39 preyalone: Another problem is that Homebrew Chicken Scheme fails, MacPorts CLISP fails, and Fink SBCL fails. I need several package managers.

20:40 amac: that is handy information

20:40 brehaut: preyalone: i cant give you any more suggestions. clojure namespaces must be in the matching directory structure. if you refuse to acknowledge that, you will never solve this

20:40 amalloy: $source str

20:40 sexpbot: str is http://is.gd/ovOFFx

20:41 preyalone: brehaut: Open my pastebin. http://pastebin.com/raw.php?i=7StS2qvW THE TUTORIAL DOESN'T WORK ON MY SYSTEM.

20:41 brehaut: preyalone: you have spent your last credit of good will.

20:41 TimMc: I'm already /ignore ing him.

20:41 Forgot to add -replies.

20:42 amalloy: i wonder why str uses an anonymous function instead of a loop

20:43 amac: can loops be lazy?

20:43 amalloy: no, but neither is str

20:43 amac: it looks like it can be

20:44 amalloy: it can't

20:44 because a string is a single atomic object

20:44 you can't return part of a string and give out the rest later

20:46 TimMc: I see this (.x (toString)) syntax all over c.core -- is there a particular reason it isn't written (.toString x) ?

20:46 amac: you can if the str is coerced into a seq

20:46 (type (seq "aoeu"))

20:46 ,(type (seq "aoeu"))

20:46 clojurebot: clojure.lang.StringSeq

20:46 TimMc: amac: The wrapper is a seq, sure.

20:47 amac: yeah, I guess it still needs to have the underlying string before it can be coerced

20:47 but that's the only use case I can think of for lazy strings

20:47 johnmn3: any clojars.org admins in the house?

20:48 TimMc: Now, you can certainly make a lazy seq of characters, and the fn could take the same args as str.

20:48 amalloy: TimMc: i think the version in c.core is (a) faster to compile, and (b) possibly more correct if there happens to be an object so dumb as to have a field named toString

20:48 amac: but when you create a str it would pull the entire lazy seq of chars

20:49 TimMc: amalloy: Ouch, I forgot about that.

20:49 I had been wondering about how to deal with the rare case of identical field and method names, and now I know. :-)

20:51 amac: .(str \a \o (delay \e))

20:51 ,(str \a \o (delay \e))

20:51 clojurebot: "aoclojure.lang.Delay@2c5810"

20:51 amac: eww

20:51 TimMc: heh

20:58 amalloy: johnmn3: i dropped an email to contact@clojars a week or so ago and haven't heard back. ping me if you get a hold of anyone

20:59 johnmn3: amalloy: yea, I forgot my password on there and sent in an email too.

20:59 TimMc: Has stuff on clojars been vetted in any fashion, or is it just a free-for-all registry of code repos?

20:59 johnmn3: pretty sure it's free-for-all

20:59 amalloy: TimMc: push anything you want

21:00 johnmn3: you register an ssh key though.. it's not like people can step on each other

21:00 amalloy: (shameless-plug http://hubpages.com/hub/Build-your-own-Clojure-toolkit mentions how easy it is to use clojars)

21:01 brehaut: amalloy: haha i was just reading that

21:02 amalloy: brehaut: after i wrote a couple articles i started getting automatic plugs from planet clojure. it was pretty neat to see that they've used yahoo pipes to automatically incorporate my clojure articles into their feed

21:03 brehaut: amalloy: yeah i noticed they did that with my site too

21:03 im tempted to make a special feed for them so its a bit more targetted

21:03 amalloy: brehaut: have you looked at the source of the pipe?

21:03 it's probably targeted enough

21:03 brehaut: amalloy: i dont have a yahoo account so i cant

21:04 amalloy: i think it looks for the word clojure in the body?

21:04 i know its not everything

21:04 amalloy: mine is like "articles by amalloy with Clojure in the title or description"

21:04 brehaut: but its picking up my short links if they match

21:04 amalloy: ah

21:04 brehaut: and that often repeats things that are in the pipe already

21:04 which (IMO) is a bit lame

21:04 amalloy: yeah i see what you mean

21:05 i only publish full-length articles so didn't consider that issue

21:05 brehaut: yeah i think its fine for most people

21:05 who have real content rather than links to other peoples content

21:18 amalloy: anyone have a link on getting started with Ring?

21:19 amac: amalloy: I've been figuring it out with the source examples, the tutorial space is light for clojure networking

21:20 brehaut: amalloy, amac: http://mmcgrana.github.com/

21:20 Lau has a couple of worked examples on his github too

21:21 also wow, lein 1.1 thats an old tutorial

21:22 amac: also, I'm using aleph which is even lighter on docs

21:22 but based on ring, so figuring ring out gets me 80% of the way there

21:23 brehaut: aleph is a bunch more (for a lack of better word) experimental

21:24 amac: yeah, I've been trying to fix a bug all week parsing form post data, can't figure out if its a problem with my code (probably), aleph (also pretty likely), or ring (doubtful)

21:25 brehaut: have you played with aleph?

21:25 brehaut: amac: its on my list but not yet

21:26 amac: bummer, I haven't run into anybody who's used it

21:26 it actually seems pretty slick, if I can get it all working

21:27 brehaut: it seems very slick yeah

21:27 amalloy: omg my computer says Hello world from Ring! this is exciting stuff

21:28 brehaut: ztellman's been putting a lot of thought into it and the channel's stuff in general. a lot of promise there in general

21:29 amac: amalloy: you're one step ahead of preyalone ;)

21:29 amalloy: hahahaha

21:29 brehaut: baha

21:29 TimMc: >_<

21:29 brehaut: amalloy: have you got it saying hello world only once?

21:29 amalloy: eh?

21:30 brehaut: make your handler approximatly (fn [req] (prn "hello") {:body "Hello, world" :status 200})

21:30 amalloy: what. noooo, side effects are evil, why would i prn

21:31 brehaut: amalloy: so that you can see it handling each request in the console

21:31 rather than just what you see from the browser

21:31 amalloy: psh

21:32 brehaut: alternative use a proxy tool i guess :)

21:32 TimMc: amalloy: At least it's not a JOptionPane

21:33 amalloy: while i'm on the topic of learning new things, someone teach me how to manage multiple swank servers/repls from emacs

21:33 * amalloy is not at all demanding

21:34 joshuac: amalloy, what I do is start the swank server on a different port and connect to it with another instance of emacs

21:34 amac: lein swank takes a port arg (defaults to 4005)

21:34 amalloy: amac: sure, i can start lots of servers

21:35 managing to use them sensibly is trickier

21:35 amac: then M-x slime-connect in emacs to whichever running server you want

21:35 amalloy: and this...what, gives me multiple slime-repl buffers, each connected to a different server?

21:35 amac: err, I guess you can only have one slime connection per instance of emacs

21:36 fire up screen and start multiple emacses

21:36 emacsen?

21:36 amalloy: barff

21:36 emacsen, i believe

21:36 amac: I've never actually had a use for that word

21:36 amalloy: hah

21:41 phenom_: what's the call to convert a keyword to a string?

21:42 amalloy: name

21:42 brehaut: ,(name :keyword)

21:42 clojurebot: "keyword"

21:42 TimMc: $findfn :phenom_ "phenom_"

21:42 sexpbot: [clojure.core/name clojure.contrib.string/as-str]

21:42 phenom_: amalloy: beautiful! thnx

21:42 * TimMc pats sexpbot on the... head? case? carapace?

21:43 amac: and oppositely, ##(keyword "aoeu")

21:43 sexpbot: ⟹ :aoeu

21:43 amalloy: amalloy for speed, brehaut for clarity, and TimMc for teaching you to go fishing your own damn self :)

21:43 $botsnack

21:43 sexpbot: amalloy: Thanks! Om nom nom!!

21:43 amalloy: TimMc: ^

21:43 TimMc: We're all winnnars!

21:43 brehaut: haha :)

21:44 phenom_: name works on any clojure.lang.Named implementation (which i believe is just keyword and symbol at present)

21:44 amac: and my advice is to solve a different problem than the one you asked.

21:44 TimMc: haha, nice

21:44 amalloy: *chuckle*

21:45 amac: $botsnack

21:45 sexpbot: amac: Thanks! Om nom nom!!

21:46 amac: who needs a dog?

21:46 sexpbot: woof!

21:46 amac: I don't even need to walk this bot

21:46 TimMc: amalloy: sexpbot doesn't shed enough.

21:47 amalloy: TimMc: submit a pull request with more hairs

21:47 TimMc: OK, I think I can manage hairy code..

21:48 Oh man, I'm so gonna write a macro called backwards-day that reverses the exprs it receives.

21:49 amalloy: TimMc: that's already been done a few times. try writing one that reverses the nested expressions too

21:49 amac: set it to only trigger on preyalone's messages

21:50 or just set all of his responses to clojure.examples.__hello__.init not found

21:50 amalloy: that's actually remarkably simple now that i think about it. (defmacro backwards-day [& exprs] (clojure.walk/postwalk reverse exprs))

21:50 TimMc: amac: That's horrible!

21:50 And yet...

21:50 amac: $botsnack

21:51 amac: TimMc: Thanks! Om nom nom!!

21:51 sexpbot: TimMc: moar plz. still hungry

21:51 TimMc: amac: Laggy. You should ask your doctor to take a look at your inner loops.

21:52 amac: hah

21:52 TimMc: amalloy: What should (bday 1 2 (bday 3 4)) do?

21:52 amalloy: (if anyone's bothered by this: i'm acting as sexpbot's puppeteer here. he really doesn't just volunteer clever complaints)

21:52 waxrose: Hello every body.

21:52 TimMc: I assume yo'd have to write it (bday 1 2 (4 3 bday))

21:53 hey waxrose

21:53 waxrose: TimMc, Howdy.

21:53 amac: I'm fairly sure one of these days I'm going to hop on the channel an sexpbot will be alive.

21:53 I'm keeping on his good side for when the revolution comes.

21:53 waxrose: Seems like I missed some excitement.

21:54 TimMc: Sort of. amalloy had his hand up a bot.

21:54 amalloy: TimMc: i guess...your fixed version would turn into (do (3 4) 2 1)

21:54 Derander: waxrose: I read that as "excrement"

21:54 amalloy: Derander: last time i typed excitement on my phone, it got auto-corrected to excrement

21:54 Derander: nice :-)

21:54 waxrose: amalloy, Don't you just love that?

21:54 TimMc: amalloy: (do (4 3) 2 1), actually

21:55 amalloy: TimMc: this shit hurts my head

21:55 TimMc: Wheee!

21:55 amalloy: also both of us forgot the second do

21:55 TimMc: yup

21:55 waxrose: amalloy, Isn't that a sign of greatness?

21:57 TimMc: The well-known saying says nothing about fools, unfortunately. :-(

21:57 waxrose: lol

21:57 amalloy: (macroexpand-all '(bday 1 2 (4 3 bday)))

21:57 (do (do 4 3) 2 1)

21:58 TimMc: \o/

21:58 amalloy: and my original version didn't work so good, since it required that everything be a seq

21:58 (defmacro bday [& exprs] (cons 'do (clojure.walk/postwalk (transform-if sequential? reverse) exprs))) ; using transform-if from my toolbox

21:59 TimMc: You wrote my macro. ;.;

21:59 amalloy: lol

21:59 waxrose: lol

21:59 TimMc: Well, I guess I can start using it now.

22:00 amalloy: TimMc: and i hereby release it under the gpl! now you can't use it without licensing your code under the gpl

22:00 TimMc: onoes

22:00 How ever shall I incorporate that into my GPL code?

22:01 (I actually don't know how GPL version mismatches are resolved.)

22:03 amac: I think the new ones infect the older versions

22:04 open source licencing is a laughably complex solution to a simple problem

22:05 http://www.opensource.org/licenses/alphabetical

22:14 Adamant: lawsuits (BSD/MIT) and the legal inability to easily invert copyright law (GPL) lead to most of the complications.

22:14 well, the fundamental ones, anyway

22:31 amalloy: ugh. someone plz improve the error message you get when you (:use (foo.core)) instead of (:use foo.core) or (:use (foo core))

22:31 ie, cause there to be an error message

22:43 phenom_: hey guys ... lets say for example we have a network service that accepts requests on a socket, does some processing with internal shared state accross every request and returns a response ... that shared state, how should it get to each of the network handlers (the one accepting/processing requests)? global variable ?

22:44 amalloy: phenom_: i'd make the server socket hold onto an atom/ref around your global state, and then either pass it to the socket-handlers or make them closures around that atom

22:47 eg, (let [server-socket (...), state (atom {})] (defn serve [] (while true (respond state (.accept server-socket)))))

22:52 phenom_: haha, making depencies explicit and forced in a way ...

23:02 amalloy: i don't see why that's funny, but sure

Logging service provided by n01se.net