#clojure log - Jun 21 2011

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

1:02 jebberjeb: why is clojure named clojure?

1:03 amalloy: jebberjeb: closures, in java? *shrug*

1:53 duncanm: la la la

2:14 sunnibo: question: i have a txt file that contains several Korean words. How can i extract only Korean words? any tips?

2:15 Cozey: Hi - are you using jetty7? Or is clj community sticking to 6 ?

2:37 raek: sunnibo: that sounds like something that is hard to do 100% correctly. but one approach could be to split the input into words and filter those that contains any Hangul characters. do you think that would work?

2:59 sunnibo: raek: the question is changed: i need to extract all Hangul characters. and i'm wondering the 'filter' part. Can i distinguish Korean chars from other chars?

2:59 I saw a solution using Character/getType. The return value 5 represents 'Other Letter'.

3:00 If i assume that my txt file contains English alphabets and Korean characters only, I think this solution is not bad.

3:01 raek: sunnibo: my idea was to check whether the character is in a certain Unicode range, like "Hangul Syllables

3:01 " range AC00–D7AF

3:01 ,(<= 0xAC00 (int \가

3:01 clojurebot: EOF while reading

3:02 raek: ,(<= 0xAC00 (int \가) 0xD7AF)

3:02 clojurebot: true

3:02 sunnibo: that sounds good.

3:02 raek: sunnibo: you can find the code charts for hangeul in the rightmost column here: http://www.unicode.org/charts/

3:02 sunnibo: ah. how can i get a character vector from a string?

3:02 raek: each PDF begins with the range

3:03 sunnibo: "가나다" -> [\가 \나 \다]

3:03 raek: sunnibo: you can use a string like a sequence directly

3:03 sunnibo: oh

3:03 raek: ,(seq "가나다")

3:03 clojurebot: (\가 \나 \다)

3:03 sunnibo: thanks a lot

3:03 raek: ,(filter #(<= 0xAC00 (int %) 0xD7AF) "x가y나z다w")

3:03 clojurebot: (\가 \나 \다)

3:05 raek: ,(filter #(any? (fn [c] (<= 0xAC00 (int c) 0xD7AF)) %) ["hello" "가나다" "åäö"])

3:05 clojurebot: java.lang.Exception: Unable to resolve symbol: any? in this context

3:05 raek: ,(filter #(some (fn [c] (<= 0xAC00 (int c) 0xD7AF)) %) ["hello" "가나다" "åäö"])

3:05 clojurebot: ("가나다")

3:06 sunnibo: yeah. wonderful code.

3:07 okay. i extract all Korean characters now. and how can i remove duplicates? by set?

3:10 (\가 \나 \가) -> (\가 \나)

3:11 ,(distinct '(\가 \나 \가))

3:11 clojurebot: (\가 \나)

3:25 raek: sunnibo: ah, just read the "i need to extract all Hangul characters" part...

3:26 sunnibo: sets are good.

3:27 ,(into #{} (filter #(<= 0xAC00 (int %) 0xD7AF) "long text that may contain 가나다 some hangeul characters"))

3:27 clojurebot: #{\가 \다 \나}

3:28 raek: sunnibo: for the file I/O part, use (clojure.java.io/reader "filename" :encoding "UTF-8") to open a text file (you can skip the encoding part if it's UTF-8)

3:29 distinct uses a set internally to remember elements already seen. the distinct elements are left in-order, unlike in sets

3:30 ,(set "가나가")

3:30 clojurebot: #{\가 \나}

3:31 sunnibo: raek: yes, i didn't say. txt files use UTF-8.

3:32 thanks always.

4:06 shtutgart: Is there a function to remove nth element from the vector?

4:08 Currently I use (remove nil? (assoc vector idx nil)) for this purpose (assuming vector doesn't have nils)

4:14 raek: shtutgart: no. vectors do not provide a non linear time way of changing the number of elements (inserting or deleting) in the middle

4:25 why are you using indexes here? when you remove an element from the middle, the indexes of all element after the middle will change

4:26 I think there is a simpler solution to the problem than using vectors and indexes

4:31 shtutgart: raek: idx is the index of an element that I want to delete

4:32 (my-remove-fn [:a :b :c] 1) => [:a :c]

4:35 raek: ,(let [v [:a :b :c], i 1] (into (subvec v 0 i) (subvec v (inc i))))

4:35 clojurebot: [:a :c]

4:36 raek: shtutgart: you can do it like that, but I don't know if it is "what you really want"

4:36 ~xy

4:36 clojurebot: xy is http://mywiki.wooledge.org/XyProblem

4:36 raek: shtutgart: where does the index come from?

4:38 shtutgart: raek: from java code; they give me an array and an index

4:40 raek: shtutgart: what are you supposed to do with the array? modify it in place? return a new one?

4:41 shtutgart: I need to operate on item with given index and all other items, than return single value

4:43 raek: is this a ListModel or something similar?

4:43 shtutgart: I think your solution with subvecs completely fits me

4:43 raek: in that case, I guess you have to do this

4:44 shtutgart: raek: no, it's Vector

4:44 raek: java-vector?

4:44 shtutgart: yes, from java.util

4:45 raek: I'm sorry, I

4:45 'm confused

4:46 are you changing a clojure vector, a java vector or a java array that you get from somewhere else?

4:46 or are you implementing an interface or something?

4:48 fliebel: Any news about the Clojure survey?

4:49 shtutgart: Sorry, I've sayed about array because recently it actually was array, but then it was changed to java.util.Vector. Anyway, the first thing I do is casting it to a clojure vector

4:51 raek: so I'm getting a java vector (that was array yesterday) and changing a clojure vector :)

5:04 khaliG: did anyone attempt the icfp contest with clojure this year?

5:22 Cozey: Hi, how to call a super method from overriden one, when using :gen-class?

5:37 hoeck: Cozey: you add an :exposes-methods {super-method-name exposed-name, ...} to the :gen-class option and in you code invoke: (exposed-name this ...) to call the exposed super method

5:38 Cozey: mhm. thanks - i'll try that

5:38 hoeck: Cozey: see also (doc gen-class)

5:57 mrBliss: fliebel: that rotating wheel on your blog drives me mad :-)

5:59 fliebel: mrBliss: Why? Imagine how the Python guy feels then.

8:48 solussd_: What's going on here: (type (conj (seq (vector 1 2 3)) 4))

8:48 ,(type (conj (seq (vector 1 2 3)) 4))

8:48 clojurebot: clojure.lang.Cons

8:48 solussd_: I expected a persistentVector, I got a Cons. :/

8:49 I thought seq returned a seq(hence) on a collection, not change its type..

8:49 ejackson: but you called seq - so its no longer a vector ?

8:49 solussd_: *sequence

8:49 ,(type (seq [1 2 3]))

8:49 clojurebot: clojure.lang.PersistentVector$ChunkedSeq

8:50 ejackson: a seq is a seq, use into to put it back into a vector

8:50 solussd_: but it is?

8:50 it seems that conj is returning a Cons

8:50 clgv: solussd_: just use ##(type (conj (vector 1 2 3) 4))

8:50 sexpbot: ⟹ clojure.lang.PersistentVector

8:51 solussd_: clgv, I know my example isn't what I'd really do.. just wondering why I end up with a Cons if I make it a seq before conj'ing

8:52 clgv: solussd_: you switch to a different type by using seq - it's a sequence after that

8:52 solussd_: conj is suppose to do the 'optimal' thing- is adding to the left side of a (seq (vector 1 2 3)) optimal?

8:53 ejackson: yup

8:53 solussd_: interesting

8:53 raek: solussd_: seq returns a sequential view of the collection. the fact that it comes from a vector is abstracted away.

8:53 clgv: and clojure can only append to the front of the sequence via a cons when you call 'conj

8:53 dnolen: ,(type (cons 4 '(3 2 1)))

8:53 clojurebot: clojure.lang.Cons

8:53 dnolen: ,(type (let [x (cons 4 '(3 2 1))] (rest x)))

8:53 clojurebot: clojure.lang.PersistentList

8:53 solussd_: raek: does it still add to the underlying vector's tree?

8:54 clgv: solussd_: no it does not

8:54 raek: solussd_: in a singly linked list, appending to the front is the only reasonable append you can do

8:54 solussd_: no

8:54 solussd_: raek: ok, does (seq [coll]) actually turn it into a singly linked list?

8:54 i.e. does it copy it?

8:54 raek: ,(conj (rseq [1 2 3]) :x)

8:54 clojurebot: (:x 3 2 1)

8:55 raek: solussd_: no. it's lazy.

8:55 you will create new seq objects when you traverse the seq, but they won't be created at the first seq call

8:56 a vector seq is basically just a reference to the vector and an index

8:56 solussd_: ok. so a seq from a vector is a lazy singly linked list and when I add to it I'm linking to the front of the lazy list? :)

8:56 raek: when you call rest on it you get a new vector seq with the index incremented

8:56 solussd_: yes

8:57 solussd_: ok- and if I (into [] (conj (seq (vector 1 2 3)) 4)), is that at least efficiently "adding" the 4 to the underlying vector and returning it?

8:57 raek: ...and when you call first on it you look up that index in the vector

8:58 solussd_: i.e. is it just returning a conj on the original vector?

8:58 raek: solussd_: well, you construct a whole new vector

8:58 solussd_: raek: but does it share structure?

8:58 raek: that does not share structure with the old one

8:58 solussd_: ah..

8:58 raek: seqs can share tails

8:59 vectors can share, well, to the left

8:59 solussd_: ,(vec (conj (seq (vector 1 2 3)) 4))

8:59 clojurebot: [4 1 2 3]

8:59 raek: and internal structure

8:59 solussd_: so that doesn't share structure either?

8:59 raek: no

9:00 only the operations that operate directly on the vector can result in a vector that shares structure

9:00 solussd_: so, the moral of the story is, don't use functions on vectors that return seqs unless you are planning on just iterating through the vector

9:00 raek: vec cannot tell that the seq is comming from a vector

9:00 solussd_: that makes sense. thanks!

9:01 raek: conj, pop, peek, assoc all return a vector that shares structure

9:03 solussd_: I was originally trying to understand how a PersistentQueue works under the hood- being a seq + vector

9:07 clgv: solussd_: there is an explanation for that in "The Joy of Clojure"

9:07 solussd_: clgv: yeah.. that's what I'm reading and I'm not sure I "get" what happens when you pop

9:08 clgv: solussd_: ok, maybe you just have to reread the paragraph. I thought it was quite well explained

9:09 solussd_: clgv: My questions is, when all the items on the seq are popped off, does it *then* wrap the vector in a new seq?

9:09 raek: solussd_: yes

9:10 it always has one vector and one seq

9:10 solussd_: well, then that makes sense. Juspt reread the paragraph.. makes sense.

9:10 clojurebot: It's greek to me.

9:12 raek: [] (1 2) --> push 3 --> [3] (1 2) --> pop 1 --> [3] (2) --> push 4 --> [3 4] (2) --> pop 2 --> [3 4] () --> pop 3 --> [] (3 4) --> [] (4)

9:12 solussd_: thanks. that was the picture in my head

9:13 clgv: *g* ascii symbols in ones head isn't a good omen, is it? ;)

9:15 raek: hrm, displaying the seq and vector in the (1 2) [3 4] probably makes more sense.. :)

9:15 solussd_: clgv: I see in ascii.. don't you? doesn't everybody?

9:15 clgv: solussd_: lol. :D

9:15 solussd_: :/

9:15 clgv: I can only see binary ;)

9:16 it's a gene defect

9:16 solussd_: maybe an evolutionary advantage

9:16 stuartsierra: There are only 10 kinds of people...

9:17 solussd_: thanks everyone- back to rereading joy of clojure. I read it as a MEAP, but figured I should read the final. :D

9:18 then someone needs to write a more advanced clojure book (or I need to find a day job writing clojure). :D

9:18 raek: There are only 11 kinds of people...

9:18 clgv: stuartsierra: exactly :D

9:20 raek: (Those who understand Gray code, and those who do not.)

9:27 Cozey: How can i invoke ant task from cake task?

9:28 bendlas: Cozey: in leiningen you use lancet, I suppose you do the same in cake

9:29 Cozey: bendlas: oh? does lein uses lancets tasks as well?

9:29 bendlas: Cozey: it does. some of them, anyway

9:30 Cozey: cake's ninjudd written something like unce for ant support in cake. but this doesn't look like an active project, and i can't get it to work under clj 1.3

9:30 uncle*

9:30 bendlas: right

9:30 i remember

9:30 Cozey: maybe lancet is the way to go

9:31 bendlas: you should be able to use lancet anyway, after declaring it as a dev depencency

9:32 Cozey: yep. i'm just starting to think that i should betray cake for lein... last few days all the missing cake features i stumbled into are working on lein

9:33 both seem active..

9:35 clgv: Cozey: lein is pretty active, I'd say.

9:35 bendlas: i feel that lein mostly is the canonical choice now

9:36 only (+) for cake is persistent JVM

9:36 Cozey: doesn't lein has a plugin for that ?

9:36 clgv: the only annoying thing when using lein is, that the uberjar building takes pretty long. dont know how that is in cake.

9:36 bendlas: OTOH (-) who wants to install ruby for building their clojure project?

9:37 Cozey: never tried - i upload the dep jars separately so i don't have a huge uberjar which uploads long

9:37 clgv: well, since I mentioned it: does anyone know a way to speed up building uberjars in leiningen?

9:38 bendlas: clgv: I found the ant task for packaging jars a bit faster

9:38 mostly because it does less (i guess)

9:39 uberjar always rebuilds before packaging (IIRC)

9:40 if you want to try that, it's pretty easy with lancet:

9:40 1) get filesets for application jar and all the libs

9:41 2) call lancet/jar with it

9:41 s/it/them/

9:41 sexpbot: <bendlas> 2) call lancet/jar wthemh them

9:42 Cozey: what about lein + additional maven tasks?

9:42 under cake it's impossible for instance to add a maven plugin to deploy to a server (like cargo plugin)

9:43 becase cake just uses maven to fetch deps, and always overwrites pom.xml

9:43 is this possible under lein ?

9:43 bendlas: lein writes a pom.xml

9:44 Cozey: is it possile to have a pom-plugins.xml or something like it ?

9:44 clgv: humm, it would probably speed up the whole uberjar taks if it had a prebuild dependency uberjar where my code just has to be added to

9:44 Cozey: in general to integrate maven tasks with lein ones?

9:44 dnolen: hmm w/ groundess analysis and DCG optimizations I think core.logic can almost completely close the gap with SWI :D

9:45 bendlas: Cozey: I'm not aware of something like that

9:48 clgv: don't think so

9:48 i think most of the time is spent in this line https://github.com/technomancy/leiningen/blob/master/src/leiningen/uberjar.clj#L75

9:49 so .. try adding ':disable-implicit-clean true' to you project.clj

9:50 clgv: bendlas: nope, I deactivated that one

9:50 bendlas: I think most is spent in unzipping and zipping my dependencies

9:50 bendlas: clgv: and uberjar still takes significantly longer than plain jar?

9:51 clgv: hm yeah, I have already quite a lot of dependencies

9:52 bendlas: humm can I convince lein uberjar to run multithreaded?

9:52 that would speed up compilation and unzipping as well

9:54 bendlas: clgv: doesn't look like it supported that

9:54 jcromartie: Why is there both filter and keep?

9:54 clgv: ;(

9:54 bendlas: but that's probably the reason for the ant task being faster

9:54 clojurebot: Reason is , and ought only to be the slave of the passions, and can never preted to any other office than to serve and obey them -- Hume

9:56 bendlas: jcromartie: filter works with a predicate and returns the original items

9:57 keep yields the results of the function

9:57 also filter filters by truthiness

9:57 and keep keeps by non-nillnes

9:58 jcromartie: ah, I missed that part

9:58 (the results)

9:59 keep has a rather lengthy implementation in the Clojure source code

10:00 for what is essentially (filter #(not (nil? %)) (map f coll))

10:01 maybe it's more performant

10:01 bendlas: jcromartie: it does, but most of it is for chunked seqs

10:02 which are indeed a perf opt

10:02 jcromartie: don't filter/map already handle chunks

10:04 bendlas: they do

10:05 jcromartie: well I won't doubt the rhickey

10:05 bendlas: but the impl of core fns is often unidiomatic for sake of performance

10:05 jcromartie: yeah

10:05 I can see how it would be, for keep

10:06 clgv: bendlas: using parallel execution has to be patched in here I guess: https://github.com/technomancy/leiningen/blob/8047e90837e0d8019a1f37d59901759966c7dfed/src/leiningen/compile.clj#L253

10:09 bendlas: clgv: maybe, but I suspect massive amounts of work would be wasted every build

10:09 clgv: bendlas: why?

10:09 bendlas: because the compiler goes to dependency namespaces and compiles them to

10:09 clgv: oh damn^^

10:10 well so this is a problem of the compiler.

10:10 bendlas: dunno, is the compiler smart enough to recognize up-to-date .class files?

10:11 clgv: it has to analyse the project and build a topological sort of the source file dependency tree - then it could easily compile in parallel

10:12 bendlas: yep

10:12 I suspect nobody is going to touch that, until C in C is underway

10:13 clgv: &(doc clojure.core/compile)

10:13 sexpbot: ⟹ "([lib]); Compiles the namespace named by the symbol lib into a set of classfiles. The source for the lib must be in a proper classpath-relative directory. The output files will go into the directory specified by *compile-path*, and that directory too must be in the classpath."

10:13 clgv: $source clojure.core/compile

10:13 sexpbot: clojure.core/compile is http://is.gd/INNeeK

11:40 edoloughlin: Is there a way of getting a directory listing without using Java?

11:42 terom: Why would you want one?

11:42 manutter: ,(doc line-seq)

11:42 clojurebot: "([rdr]); Returns the lines of text from rdr as a lazy sequence of strings. rdr must implement java.io.BufferedReader."

11:43 edoloughlin: terom: Purity? There are other non-Java file i/o functions

11:43 * manutter was wondering if you could just get a line-seq from a directory path, but isn't sure

11:44 manutter: well it was a nice thought

11:44 terom: edoloughlin: well you could then define some wrapper functions of our own, couldn't you?

11:45 edoloughlin: Back to (. something) - I just don't like the look of it...

11:46 Fossi: there was some file-list or such in ex-contrib iirc

11:48 file-seq

11:48 it's not recursive though iirc

11:49 edoloughlin: Fossi: great! Don't need it to be recursive. Thanks.

11:52 dnolen: edoloughlin: to do many useful things in even in pure Clojure you better get used to (. something)

11:53 I use (. something) when necessary and I'm not using *any* Java libs at all.

11:55 manutter: argh file-seq not line-seq

11:55 I was close

11:57 dnolen: fliebel: as it usual turns out I was entirely wrong about interleaving search being the bottleneck in core.logic. I always want to blame interleaving search :)

12:09 fliebel: dnolen: Why do you want to blame it, and why wasn't it the problem?

12:11 dnolen: fliebel: heh because I didn't have any better ideas? the issue is when you're parsing you really don't want to create a logic var and a unification operation on every single character you parse, which is why it was crazy slow.

12:11 fliebel: dnolen: So how does Prolog get away with not defining symbols and unification for every symbol?

12:12 dnolen: fliebel: groudness analysis. When parsing you know the input is completely ground, you don't need unification or logic vars at all.

12:13 fliebel: it's actually kind of cool, basically if we have ground terms we can do some tricks behind the scenes to defer to regular Clojure fns.

12:14 fliebel: dnolen: That'd awesome yea

12:15 dnolen: instead of nrevo taking taking 4100ms to reverse a list 1e3 times, it takes 18ms if we see that an argument is ground! Just like it does in Prolog.

12:35 technomancy: bendlas: so are you interested in speeding up uberjar? =)

12:47 ilyak: hi *

12:47 my ccw in eclipse doesn't build my clojure files

12:47 It did for a brief period, but no longer

12:47 Any ideas on how to make it build those?

12:48 fliebel: cemerick: Ah, there you are! I've been hitting refresh on your blog all day :P ... at least checked twice.

12:48 ilyak: (I mean compiling them to some directory)

12:49 cemerick: ilyak: The builder only runs when you have a REPL running associated with the project.

12:50 fliebel: don't stress, probably no results until Thursday-ish

12:52 ilyak: I started repl

12:53 How do I make it compile something?

13:03 amalloy: &(doc compile)

13:03 sexpbot: ⟹ "([lib]); Compiles the namespace named by the symbol lib into a set of classfiles. The source for the lib must be in a proper classpath-relative directory. The output files will go into the directory specified by *compile-path*, and that directory too must be in the classpath."

13:04 ilyak: Obviously I want that to just happen when I use an IDE

13:06 technomancy: AOT compile or just regular compile?

13:10 ilyak: just regularly compile (gen-classes) especially

13:10 Because I have code that depends on those gen-classes in runtime

13:10 technomancy: gen-class requires AOT compilation

13:11 if you do that from your IDE your project is going to have serious portability issues

13:12 your IDE should delegate that functionality to your build tool

13:15 cemerick: It does (or, can); there are maven, gradle, and ant builders for Eclipse.

13:16 Cozey: Is putting clojure files directly under src/ is the only option in lein? Where should I put java sources, static web files, web.xml etc ?

13:16 technomancy: Cozey: you can customize :source-path

13:17 Cozey: you can keep java in a separate path or in src/, whatever you please. not sure about the webby stuff.

13:17 Cozey: ok thanks - and how will this the be packaged? is there some source file / doc to read about it?

13:18 it depends how lein will war-pack it

13:18 technomancy: well that's up to the lein-ring plugin

13:18 for the built-in stuff "lein help tutorial" should cover you

13:19 Cozey: tutorial - thanks - i need that. I just left cake behind :'-/

13:26 why even with sucessful tasks I get That's not a task. Use "lein help" to list all tasks.

13:26 ?

13:27 technomancy: never heard of that before. context?

13:27 Cozey: wait - i just noticed i have lein 1.3.1 installed in local/bin - it must be that

13:27 yep

13:28 chouser: argh!

13:30 stuartsierra: is it possible that lazy-test may consider two sets to be unequal if they are in a different order?

13:31 oh wait, maybe it's my fault. :-]

13:35 amalloy: chouser: when i had trouble with set equality, it was because (not= (int 1) (long 1))

13:35 well. they *are* =, but they don't hash the same

13:36 Cozey: technomancy: does lein have something like 'context' or 'profile' ?

13:37 technomancy: Cozey: I don't know what that means.

13:37 amalloy: fixed in 1.3 iirc provided you're not using java methods

13:38 Cozey: technomancy: a profile could be a specific configuration for running a project and packaging it: for instance a different sets of db configuration files, etc

13:40 technomancy: Cozey: that's typically done by the classpath; you can put config in test-resources/ vs resources/ depending on if you want it in development vs the final product

13:40 Cozey: ok - and if have have a few flavours of the final product ?

13:41 technomancy: depends on how you're deploying it, I guess

13:51 TimMc: ,(.hashCode (long 1))

13:51 clojurebot: 1

13:51 TimMc: amalloy: Do you mean -1?

13:52 chouser: amalloy: ah, thanks.

13:52 amalloy: &(#{(long 1)} (int 1))

13:52 sexpbot: ⟹ nil

13:52 amalloy: TimMc: ^

13:52 TimMc: Ah, weird.

13:52 chouser: in my case I've got two things that look like maps, but one is a reify I made with broken hashCode and equiv

13:52 so definitely my fault.

13:53 amalloy: chouser: i kinda think clojure.core/hash-set has a broken equiv

13:53 chouser: that number-hashing problem is fixed in 1.3

13:53 TimMc: What's going on with that example, amalloy?

13:53 The .hashcodes are the same.

13:54 Cozey: technomancy: my setup is a bit strange - but i guess i'll just use lancet to generate wars - thanks!

13:54 amalloy: TimMc: i didn't look deeply into it. i'm guessing it tests with .equals rather than RT.equiv

13:54 chouser: & (= (long 1) (int 1))

13:54 sexpbot: ⟹ true

13:54 TimMc: OK

13:54 chouser: & (.equals (long 1) (int 1))

13:54 sexpbot: ⟹ false

13:54 __name__: & (== (long 1) (int 1))

13:54 sexpbot: ⟹ true

13:54 TimMc: Ah, so the hashes collide properly, but the equality check is bad.

13:55 Seems likely.

13:55 amalloy: TimMc: yeah, just checked

13:55 uses Util.equals, not Util.equiv

13:55 in APersistentMap.java

13:59 TimMc: actually the code is more labyrinthine than i thought; i'm now not actually sure i found that code that's to blame

14:03 dnolen: amalloy: that's a numerics issue, not a equals/equiv issue. and it's resolved in 1.3.0 as chouser said.

14:04 amalloy: dnolen: cool beans

14:05 dnolen: fwiw, transliterated yesterday's java to clojure, and it's only about 5-10% slower

14:06 dnolen: amalloy: nice! that seems about right, 1.2.X right? seems like 1.3.0 has the 5-10% perf boost to make up the difference.

14:06 amalloy: yes, 1.2.1

14:06 i tried 1.3 briefly but had some weird issues so gave up

14:24 gfrlog`: is there a standard ring middleware for the classic _method hack?

14:27 * seancorfield__ is at JAXconf today in San Jose

14:28 seancorfield__: Clojure got a little mention in Rod Johnson's keynote but he was a little dismissive of "language experiments" on the JVM

14:32 * gfrlog` is thinking maybe compojure has it built in

14:34 dnolen: seancorfield__: anything specific?

14:44 seancorfield__: dnolen: no, it was just his off-hand comments about non-java languages on the jvm - and he feels that java is the last breakout language, everything else will always be minority

14:45 chouser: really? did he mention JavaScript?

14:45 seancorfield__: but he did tell his (mostly) java dev audience that java devs need to get used to learning new languages frequently :)

14:46 at one point he commented that using noSQL datastores involved writing a lot more code than using RDBMS (in the context of hibernate / jpa)

14:46 my response (on twitter) was that he's just using the wrong technology :)

14:52 dnolen: i found it interesting that 4square now has 150K of Scala.

14:52 I can't imagine a Clojure project ever having that much code.

14:53 ilyak: Why? If it's properly structured

14:54 For example, you might have a task framework and hundreds of tasks

14:54 hiredman: that is a lot of code

14:55 dnolen: ilyak: if it's properly structured I don't see how you could *ever* get to 150K of Clojure.

14:55 ilyak: I once had a CMS which was 150k lines java

14:55 seancorfield__: 150k lines of java is not big tho

14:55 ilyak: I managed to bring it down to something like 45k

14:55 hiredman: our clojure code base at work is only 20,071

14:55 technomancy: I wonder how many people they have

14:55 ilyak: There are some hairy features that mean a lot of code

14:56 dnolen: 150K of anything should be enough to make anyone raving mad.

14:56 chouser: hiredman: wow, that's a *lot* of clojure

14:56 technomancy: could be spread across multiple codebases

14:56 ilyak: I've recently implemented one feature in clojure, and it's 600 lines

14:56 technomancy: hiredman: with tests?

14:56 ilyak: Maybe I can factor out some common code, but it won't compress much

14:57 (counting all lines with wc -l, of course)

14:57 hiredman: technomancy: yes

14:57 without comments, blank lines, etc

14:57 using cloc

14:57 chouser: yes

14:58 TimMc: Count the open parens. :-)

15:03 wastrel: i sawa guy with a lisp t-shirt today

15:03 (loop (print (eval (read))))

15:04 ^^^ the t-shirt

15:04 stuartsierra: nice

15:10 hugod: hiredman: cloc supports clojure? or just generic lisp?

15:10 hiredman: generic lisp

15:10 cloc --force-lang=lisp,clj

15:13 hugod: pallet totals 26,994

15:16 dnolen: core.logic 3451

15:16 hiredman: hugod: to be fair pallet now seems to contain most of what was the jclouds clojure api

15:17 or I guess not, just abstractions on top of jcloud's

15:17 hugod: hiredman: I would say the latter

15:18 hiredman: still a lot of code

15:18 hugod: 17823 without tests

15:44 TimMc: wastrel: (-> (read) (eval) (print) (loop)) :-P

15:44 wastrel: that is not what the shirt said :[

16:01 gfrlog`: (->> (read) (eval) (print) (do (recur)) (loop []))

16:01 that almost works :/

16:02 chouser: gfrlog`: cool! what breaks?

16:02 gfrlog`: chouser: it's the diff between -> and ->>

16:02 you want one for (do) and the other for (loop)

16:03 ,(doc read)

16:03 clojurebot: "([] [stream] [stream eof-error? eof-value] [stream eof-error? eof-value recursive?]); Reads the next object from stream, which must be an instance of java.io.PushbackReader or some derivee. stream defaults to the current value of *in* ."

16:03 hiredman: you can switch mid-stream

16:03 gfrlog`: oh I didn't know read was a function

16:03 hiredman: please tell me what you mean and my code will become so much nicer.

16:03 hiredman: (-> (read) (eval) (print) (do (recur)) (->> (loop [])))

16:04 gfrlog`: ah of course; it's a bit of nesting but it's still very nice.

16:04 I am humbled for never having thought of that.

16:07 chouser: (-> (read) eval println (do (recur)) (->> (loop [])))

16:07 gfrlog`: chouser: does (read) play nice with (eval)?

16:07 hiredman: really tou want prn

16:07 gfrlog`: when I run that at the repl I don't think (read) returns

16:07 hiredman: you

16:08 chouser: hiredman: yes

16:08 hiredman: or pprint

16:08 if pprint didn't print vars ridiculously

16:08 chouser: ooh

16:09 gfrlog`: anybody know if the original form is valid in clisp or scheme?

16:09 chouser: bah, pprint doesn't flush

16:11 gfrlog`: okay, so it works as long as I don't run it from a repl :)

16:12 (ns foo) fails though

16:13 chouser: (fn -loop [_] (-> (read) eval prn -loop))

16:13 cemerick: Would it just be cheating to define a function loop*?

16:13 chouuuuuuuuuuuuuser!

16:13 chouser: cemerick: mua-ha-ha

16:13 * cemerick does a khaaan impression

16:14 gfrlog`: cemerick: loop* takes care of the recuring?

16:15 technomancy: prn is underrated

16:15 gfrlog`: (inc prn)

16:15 sexpbot: ⟹ 1

16:15 technomancy: especially for inserting debugging statements; if you use prn for debugging exclusively it's a lot easier to grep for stuff you accidentally left in

16:15 cemerick: gfrlog`: I misspoke — a separate loop* macro would make the (almost) original (loop* (print (eval (read)))) form "just work"

16:15 gfrlog`: cemerick: right.

16:16 technomancy: and you use (println) for normal output?

16:17 technomancy: right

16:17 gfrlog`: yeah, that's how I use them too

16:18 Raynes: technomancy: If only I'd remember to grep.

16:18 technomancy: pre-commit hook can do it

16:22 gfrlog`: cemerick: could cheat even harder and exclude clojure.core/loop from the ns, and just call the macro (loop) :)

16:22 I guess at that point you could cause almost any form to do anything you want.

16:23 cemerick: gfrlog`: feh, I forgot that loop* was the actual special form for loop. You can redefine loop freely; no need to exclude.

16:25 chouser: oh, nice. (fn loop [_] (-> (read) eval prn loop))

16:25 cemerick: good call

16:25 gfrlog`: chouser: that'll fill the stack, right?

16:25 chouser: that's T-shirt-worthy

16:25 gfrlog`: yep

16:26 Raynes: technomancy: Good idea.

16:26 gfrlog`: the best repls are ticking time bombs

16:26 chouser: so only a thousand or so commands before the JVM quits on you

16:26 gfrlog`: gives a human side to the repl; it needs a break.

16:28 arohner: chouser: that makes a good #clojure_is, as well

16:28 chouser: hm, maybe!

16:29 well, except that's not the real repl, thank goodness

16:29 arohner: yeah, but it's a repl that will fit in a tweet

16:29 chouser: heh

16:30 gfrlog`: heck you could probably fit two repls in a tweet

16:30 four?

16:30 ,(count "(fn loop [_] (-> (read) eval prn loop))")

16:30 clojurebot: 39

16:30 chouser: gfrlog`: tweet it and I'll RT

16:31 or TimMc should

16:31 gfrlog`: truedat

16:32 chouser: pity about needing a dummy value when called

16:32 but [&[_]] is too scary

16:33 gfrlog`: (fn loop ([] (loop nil)) ([_] (-> (read) eval prn loop)))

16:33 and then it's no longer pretty

16:34 chouser: right

16:35 cemerick: Those that prefer to see the (mostly) original forms might like: https://gist.github.com/99f34654a5ec443834d6

16:36 gfrlog`: cemerick: I am surprised loop* works that way

16:36 cemerick: why?

16:36 clojurebot: http://clojure.org/rationale

16:36 chouser: heh

16:36 gfrlog`: cemerick: I guess I assumed it was a function

16:36 guess it's not

16:37 also because the source of clojure.core/loop has so much stuff in it before it gets to loop*

16:37 cemerick: loop is a macro already, but that's an impl detail so that destructuring and such can be folded into loop

16:44 Raynes: Heh, Leiningen is on homebrew. Whataya know.

16:44 I guess cake is too.

16:45 cemerick: scary

16:46 edoloughlin: I have a (def some-var (fn-that-gets-data)) in a .clj file I'm (require)'ing but (fn-that-gets-data) isn't called. Do I need an explicit (init) fn in that file?

16:53 mabes: why would renaming my jar cause the Main-Class to be undefined? (java.lang.NoClassDefFoundError) The manifest-file doesn't look like it depends on the jar name...

16:53 some fundamental jvm issue I don't understand I'm sure...

16:53 cemerick: edoloughlin: Either the file you want to load isn't actually being loaded, or fn-that-gets-data is being called, but doing something you're not expecting.

16:54 Raynes: cemerick: You've seen me in person: would I look decent with green hair?

16:55 cemerick: edoloughlin: that is to say, no, you don't need an (init) fn (not sure what that would do you in general). If fn-that-gets-data is accessing a database or something, then having that happen when the file is loaded is generally not recommended, tho.

16:55 Raynes: I'm not sure I would ever recommend green hair to anyone.

16:56 That said, it would look perfectly good on you. :-)

16:56 Raynes: So far, you're the only person I've asked that didn't just say "do it".

16:56 I was thinking of making an "I'm with @stuartsierra t-shirt" and dying my hair green before the Conj.

16:57 Move the ending quote to wherever it is appropriate.

16:57 Good thing I don't mismatch parentheses as well as I mismatch quotes.

17:00 edoloughlin: cemerick: Thanks. It was at the bottom of a chain of (require)s that turned out to be broken. It's just (slurp)ing data from a text file.

17:04 redinger: Raynes: We joked about doing the green hair last year

17:04 It's a joke that's been made this year, too

17:04 I doubt any of us will do it :)

17:04 edoloughlin: (declare) can't be used for non-public functions? A little inconvenient.

17:06 Raynes: redinger: I'm actually going to. I'll do it for all of you. I'll be the martyr.

17:07 redinger: You should make sure Stuart's going to do blue this year. I haven't confirmed that yet

17:08 Raynes: He should try pink.

17:09 cemerick: edoloughlin: (def ^:private foo) will do the same thing.

17:09 stuartsierra: Pink is not my color.

17:10 And green would make me look like a zombie.

17:10 * stuartsierra ducks out

17:11 Raynes: I bet he'd find it amusing that in my IRC client, his name is pink.

17:11 TimMc: green here

17:12 wastrel: green

17:12 ^5 TimMc

17:12 Raynes: you're pink tho

17:13 Raynes: You're olive green.

17:13 edoloughlin: cemerick: Thanks.

17:17 cemerick: Doesn't seem to do what I need. I just wanted to forward-declare a private fn so I can keep all privates at the bottom of a file.

17:19 hiredman: edoloughlin: if you use declare + defn- I think you should be fine

17:20 edoloughlin: hiredman: I tried that but I get a compile error.

17:26 hiredman: oh really, which one?

17:28 edoloughlin: var fn-name is unbound, when I try to call it

17:29 Just checked, and it works in the REPL(!)

17:29 Are there any gotchas with (declare) and namespaces?

17:34 manutter: edoloughlin: are you by any chance using your private fn inside a macro?

17:36 edoloughlin: manutter: Had the same thought. The call was wrapped in a (dbg) macro but I've removed it and still get the same error.

17:36 manutter: ,(macroexpand '(declare foo))

17:36 clojurebot: DENIED

17:37 manutter: clojurebot: :P

17:37 clojurebot: Pardon?

17:37 manutter: Ok, local repl: (macroexpand '(declare foo)) ==> (do (def foo))

17:39 declare isn't really doing anything fancy, hmm

17:39 edoloughlin: manutter: Don't want to waste your time. The simple case works for me in the REPL. It's something specific/weird with my code. I'll bang away at it…

17:40 manutter: edoloughlin: np, I'm just killing time atm

17:45 edoloughlin: manutter: Appreciated.

17:50 manutter: If you're still killing time and don't mind noob-Clojure, I've extracted the problematic code from my project: https://gist.github.com/1038986

17:51 hiredman: (def templates (get-templates "template-dir"))

17:52 you are calling it before it is defined

17:52 manutter: yeah, the def happens immediately

17:52 edoloughlin: hiredman: I thought that's what (declare) is for?

17:53 hiredman: declare lets you reference a var before it is defined, not actually use it's value

17:53 edoloughlin: Oy!

17:53 Thanks.

17:53 hiredman: (declare foo) (defn bar [] (foo 1)) (defn foo [x] (inc x))

17:54 edoloughlin: One more, small step on the path to Enlightenment.

19:53 ndimiduk: i have a question while debugging a multimethod dispatch

19:54 my dispatch function looks like: (fn [a b & c] [(type a) (type b)])

19:54 and i installed a default method: (defmethod foo :default [a b & c]

19:54 {:default [(type a) (type b)]})

19:55 for debugging anyway

19:55 so invoking foo with parameters i expect to dispatch correctly hits my :default and prints the vector

19:56 but when i remove the :default i get an exception No method in multimethod 'foo' for dispatch value: clojure.lang.LazySeq@bc83857c

19:56 this is unexpected.

19:57 dnolen: ndimiduk: were you expecting a silent failure?

19:57 ndimiduk: my method implementations are installed against vectors of classes

19:57 and i'm expecting isa? to correctly handle class hierarchies

19:57 which it does when i invoke it at the repl

19:58 dnolen: no, i was expecting dispatch to work the way i expected ;)

19:58 dnolen: ndimiduk: so you're handling lazyseq ?

19:59 wow Clojure 1.3.0 beta

19:59 ndimiduk: technically yes. i'm dispatching against vectors of classes

19:59 so, [String Integer], for instance

19:59 dnolen: ndimiduk: but where is the lazyseq coming from? it must be coming from somewhere.

20:00 ndimiduk: i presume it's the vector itself

20:01 oh, curious

20:01 user> (isa? [] clojure.lang.LazySeq)

20:01 scgilardi: I tried your dispatch function and passed 3 3 and 3 (long 3) and got the right behavior

20:01 like "no dispatch value for [Integer Integer]" for 3 3

20:01 ndimiduk: user> (isa? (type []) clojure.lang.LazySeq)

20:01 false

20:01 hiredman: correct

20:01 scgilardi: (clojure 1.2.1)

20:02 hiredman: vectors are not sequences, lazy or otherwise

20:02 ndimiduk: in that case, i have no idea where the LazySeq is coming from

20:02 scgilardi: what did you pass in?

20:03 hiredman: I imagine you did a map or a filter on a vector, the result of which is a lazyseq

20:03 ndimiduk: my dispatch-fn is (fn [a b & c] [(type a) (type b)])

20:03 technomancy: have you changed your dispatch function since starting your process?

20:04 once you set your dispatch function, it can never be changed

20:04 hiredman: ndimiduk: but what are a and b?

20:04 ndimiduk: no, but i'll restart the vm

20:04 amalloy: ndimiduk: you're never going to get (isa? [String Integer] [Object Object]) to be true, which it sounds like is what you were hoping for

20:04 ndimiduk: it's so easy to do with M-x clojure-jack-in ;)

20:05 scgilardi: hiredman: that dispatch-fn can't return a dispatch value that's a lazy seq

20:05 ndimiduk: technomancy: maybe i had changed the dispatch-fn!

20:06 because this appears to dispatch correctly now

20:06 "ah hah!"

20:06 :D

20:06 thank you!

20:06 technomancy: don't thank me, blame whoever broke defmulti

20:06 it used to work right

20:07 =\

20:07 ndimiduk: amalloy: i'm curious why you say that

20:07 > (isa? [String Integer] [Object Object])

20:07 true

20:07 hsbot: Not in scope: `isa'Not in scope: data constructor `String'Not in scope: data constructor `Integer'Not in scope: data constructor `Object'Not in scope: data constructor `Object'Not in scope: `?'

20:08 amalloy: ndimiduk: i see. i didn't realize isa? special-cased vectors for just this purpose

20:09 ~source isa?

20:09 dnolen: amalloy: otherwise multimethods would be much less useful.

20:09 amalloy: dnolen: indeed, and i'd assumed that was the way of things

20:11 ndimiduk: okay, related question

20:11 i cannot use the underscore trick in my dispatch vectors

20:11 [_ String] doesn't work

20:11 amalloy: Object

20:12 ndimiduk: given that i'm using class hierarchies, i should fall back on Object?

20:12 *nod*

21:08 amalloy: ndimiduk: fwiw, there's no "underscore trick" at the language level: _ is just another symbol, which conventionally means "i don't plan to use this"

21:08 &((fn [_] (inc _)) 4)

21:08 sexpbot: ⟹ 5

21:12 ndimiduk: amalloy: oh, interesting. i thought it was a special case in the various macros and special forms.

21:12 dnolen: ,(macroexpand '(fn [_]))

21:12 clojurebot: (fn* ([_]))

21:13 ndimiduk: there we have it!

21:13 dnolen: ,(macroexpand '(let [[_ _ _] [1 2 3]])

21:13 clojurebot: EOF while reading

21:13 dnolen: ,(macroexpand '(let [[_ _ _] [1 2 3]]))

21:13 clojurebot: (let* [vec__408 [1 2 3] _ (clojure.core/nth vec__408 0 nil) _ (clojure.core/nth vec__408 1 nil) _ (clojure.core/nth vec__408 2 nil)])

21:14 ndimiduk: is there not macroexpand-all ?

21:14 amalloy: it's in clojure.walk

21:14 ndimiduk: how do i see let* expanded inline?

21:14 ah

21:14 amalloy: but let* is the lowest level. it's not a macro

21:17 gfrlog`: is it a special form?

21:17 ,(macroexpand '(let [x 12] (inc x)))

21:17 clojurebot: (let* [x 12] (inc x))

21:18 gfrlog`: can't be a function...

21:19 amalloy: gfrlog`: well, it's not a macro and it's not a function...

21:19 gfrlog`: then it must be a var!

21:19 :)

21:19 er, a symbol. Um. a value?

21:20 amalloy: a mutable cons cell!!!1

21:20 * gfrlog` chuckles

21:20 gfrlog`: that's a variant of a prison cell?

21:21 I think erlang lets you use cons cells as arbitrary 2-tuples

21:23 I'm working in a language w/o persistent-immutable data structures, and I'm pretty sure the algorithm I'm writing practically requires them :|

21:23 It's hard for me to tell if that's actually the case or if I've just been using clojure for so long that I can't tell the difference.

21:36 rhdoenges: what is a good resource from which to learn clojure?

21:36 clojurebot: I don't understand.

21:36 rhdoenges: I don't know lisp very well either.

21:41 headlessClown: Rich Hickey's early talks on Clojure are a good start.

21:42 There's also a small collection of books but I'd recommend the presentations first

21:50 jcromartie: Anybody using Compojure in a production app?

21:50 I'm basically flipping a coin between Rails and Compojure here.

21:52 I guess it's better to just try it :)

21:52 TimMc: Give people maybe 20 minutes to see your question.

21:53 (I'm sure at least several people are using it in production.)

21:54 amalloy: jcromartie: well, 4clojure.com - not exactly enterprise-scale, but "production"

21:54 jcromartie: heh

21:54 amalloy: jcromartie: actually, i guess geni is using it too

21:54 jcromartie: well we're about to undergo a big rewrite of our product

21:54 http://www.geni.com/ ?

21:54 amalloy: yeah

21:55 jcromartie: neat

21:55 amalloy: jcromartie: but i only started working here recently. check with ninjudd or lancepantz for an official statement about how *much* it's being used

21:56 jcromartie: ah ha

21:56 well this would be "from scratch"

21:56 amalloy: anyway, with that i guess i'm off. good luck with your rewrite

21:56 jcromartie: obviously certain frameworks give you a faster time to "get off the ground"

22:50 rhdoenges: headlessClown: sorry, I left for a bit. I'll take a look at those presentations.

23:30 Raynes: amalloy: There is some Ruby in there as well. Not sure how much we're using Clojure for the web side. I'll have to ask Justin.

Logging service provided by n01se.net