#clojure log - Oct 25 2009

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

0:51 qed: how do you compare to strings

0:51 like (= str str)

0:51 or (== str str)

1:04 danlarkin: (doc =)

1:04 (doc ==)

1:04 scottj: qed, =

1:21 defn: How do I do a decrementing while loop in clojure?

1:22 I'm taking some input to this function, an integer

1:22 I want to decrement that integer until a function on the same input is true

1:22 and return that integer

1:26 lisppaste8: cema pasted "md5" at http://paste.lisp.org/display/89237

1:29 Guest16869: defn: for example like this: (defn foo [n] (if (<= n 3) n (recur (dec n))))

1:30 defn: danlei: what about with true/false?

1:30 danlei: what do you mean?

1:32 defn: danlei: http://pastie.org/private/dg1vj8nxhvmk00hjw0jpg

1:32 that first function, reverse-and-test is testing to see if the input and the reverse of the input are equal

1:32 it takes an int

1:33 in test-down we want to sart at 998001, and decrement that number until we find a palindrome

1:33 danlei: does that make sense?

1:36 danlei: defn: (defn palindromep [n]

1:36 (= n (read-string (apply str (reverse (str n))))))

1:36 defn: if you use that instead of (<= n 3) in the example above, it'll work

1:36 don't know if it's elegant, I just followed the string-reversion approach

1:37 (defn foo [n] (if (palindrome? n) n (recur (dec n)))) [untested]

1:39 defn: string-reversion approach?

1:39 danlei: number -> string -> reverse -> number

1:39 defn: are you a Haskell guy?

1:40 the '->'s make me suspicious

1:40 danlei: no :)

1:42 defn: that doesn't work

1:42 danlei: (palindrome? 11) true

1:42 (palindrome? 12) false

1:42 what shouldn't work there?

1:43 defn: that works fine

1:43 danlei: (defn find-palindrome [n]

1:43 (if (palindrome? n)

1:43 n

1:43 (recur (dec n))))

1:44 defn: but let's say we're starting at the number 998001 and want to test every number, decrementing by 1, until we find a case that is true

1:44 danlei: (find-palindrome 15)

1:44 11

1:44 I don't see the problem, can you elaborate?

1:44 or, if you don't like recur ...

1:45 (first (drop-while #(not palindrome? %) (iterate dec 998001))) [untested]

1:46 defn: java.lang.NumberFormatException: Invalid number: 000899


1:46 danlei: ah, ok

1:46 wrap it in a try block

1:46 not elegant, but should do

1:46 defn: this started out so pretty

1:47 and now is descending into a pool of liquid shit

1:47 lol

1:49 danlei: or just use Integer/parseInt instead of read

1:54 defn: btw. I tested it and it found the number without any problems

1:55 (without changing anything)

1:55 qed: even from 998001

1:55 ?

1:56 oopa

1:56 defn: even from 998001?

1:57 danlei: with parseInt: (defn palindrome? [n]

1:57 (= n (Integer/parseInt (apply str (reverse (str n))))))

1:57 (first (drop-while #(not (palindrome? %)) (iterate dec 998001)))

2:03 defn: thanks

2:04 danlei: not without changing anything tough: forgot () around (palindrome? %) above

2:08 defn: this is better: (first (filter palindrome? (iterate dec 998001)))

2:08 defn: nice filter

2:08 thanks

2:09 danlei: welcome

2:12 defn: danlei: could you explain how (let [products (for [a (range 100 1000) b (range 100 a)] (* a b))] (reduce max (filter palindrome? products))) works?

2:12 I don't understand the [ [ []]] stuff within the let, nor how it is passed forward to the reduce max fn

2:13 qed: im still here

2:13 fwiw

2:22 danlei: defn: (for [a (range 100 1000) b (range 100 a)] (* a b)) iterates for a from 100 to 100 and b from 100 to a, computing the product of them. this gets bound to procucts, which is then passed to filter in the body of the let

2:24 defn: try to reduce the code to smaller examples, and you'll understand. like: (for [x '[a b] y '[c d]] (list x y)) will give you the permutations of [a b] [c d] ...

2:25 where in [x y] x is out of [a b] and y is out of [c d]

4:37 yason: In an agent action, how do I know which agent was it sent to?

4:38 If I'm to resend the action again from the action itself, I kind of need to know the agent. ants.clj used *agents* that was defined nowhere in ants.clj but didn't seem to be in Clojure 1.0 either.

4:48 cgrand: yason: *agent*

4:48 is bind to the current running agent

4:53 yason: cgrand: I saw that and I think I tried that; perhaps I'll cross-check my experiments. Was it documented somewhere?

4:54 hiredman: it is

4:55 also documented is the fact that agents hold sends until the completion of an action

4:56 yason: The docstring for *agent* is there, perhaps I just didn't find it on the Clojure website.

4:56 cgrand: yason: http://clojure.org/api#toc9

4:56 yason: cgrand: of course, thanks!

4:56 cgrand: but no mention of it on clojure.org/agents

4:57 yason: cgrand: would've helped if it had been mentioned on the Agents page :)

6:18 ambient: threads are still completely controlled with Java interop, right?

6:18 and the message passing between threads

6:20 * ambient thinks threads violate the ACID principle but oh well...

6:32 Chousuke: ambient: you can use any of the clojure concurrency constructs instead of using threads directly

6:33 but yeah, if you do need full control for some reason, it's done via Java interop.

6:33 ambient: but if i need to run high-performance computing in the background and send and receive messages from and to that "engine"?

6:34 what would be the best way to do this with clojure?

6:35 (not HPC, just fast math)

6:36 Chousuke: hmm.

6:37 ambient: the point is to control it from REPL like this: (start-engine) (send-stuff some-stuff) (stop-engine)

6:37 Chousuke: well, you might be able to use watchers.

6:37 and an agent for serialising the message sends

6:38 ambient: ok, going to check out watchers

6:39 the engine might run with IO call-back thread

6:39 minus thread

6:40 basically it can be considered as an audio mixer that's constantly sending data. (send-stuff) sends a buffer that contains some information how to generate a wave

6:40 or changes some values in the engine

6:41 if it got no inputs, it just generates and plays silence

6:41 Chousuke: I guess you should just use plain threads.

6:55 AWizzArd: Is it only me, or do you also see http://github.com/richhickey/ as pretty empty?

6:55 ambient: AWizzArd only you

6:55 AWizzArd: ah ok, website is back

6:55 ambient: depending of your definition of empty

6:56 AWizzArd: got a 404, nginx

6:56 ambient: k

6:56 http://downforeveryoneorjustme.com/ is pretty useful site

6:58 * ambient wonders if donating to clojure is tax deductable...

7:57 ambient: anyone care to interpret this error message? java.lang.IllegalStateException: src already refers to: #'amb.synth.audioloop/src in namespace: amb.synth.audioloop (audioloop.clj:1)

8:16 if i have (def src foo) somewhere else and then try (let [src bar] ...) it gives an error?

8:17 AWizzArd: no

8:18 You shadow the def'ed src with your let, but this throws no error.

8:18 ambient: if i have src defined in amb.synth.engine and try to (def src foo) in amb.synth.audioloop, which uses ...engine it gives an error?

8:19 what is weird that i don't have "src" anywhere in my code

8:19 AWizzArd: That could throw an error, because src is imported and you try to name something else like that.

8:19 ambient: it's some reserved variable?

8:19 AWizzArd: No

8:20 do you know in which package src is?

8:21 ambient: hmm, (ns (:use)) doesn't seem to inherit the uses

8:21 amb.synth.audiochan > amb.synth.engine > amb.synth.audioloop => audioloop can't find audiochan

8:22 so perhaps all the error were caused by leftovers in the SLIME environment

8:25 yep

8:29 AWizzArd: you started a fresh jvm?

8:29 ambient: yes

8:40 adityo: hello

8:40 AWizzArd: Hi Adi

8:42 adityo: hey AwizzArd :)

8:43 im trying to traverse a directory tree , get something from each file

8:43 ambient: clojure really needs a native power function :/

8:43 adityo: (for [file (file-seq (File. "dir"))])

8:44 yet i get an error FileNotFoundException (is a directory)

8:48 spuz: Does anyone know what this error means? "java.lang.IllegalArgumentException: recur arg for primitive local: x must be matching primitive"

8:52 This seems to happen when I try to cast a local variable to a primitive type inside a 'loop' definition

9:01 chouser: spuz: you need to make sure that the matching arg in the 'recur' is also primitive

9:04 spuz: chouser: if I say (let x 2.0), is x not a primitive?

9:04 or (let [x 2.0]) even

9:05 chouser: spuz: right, literal numbers are boxed

9:05 so instead try (let [x (double 2.0)])

9:05 spuz: chouser: ah ok

9:07 AWizzArd: adityo: did you try (.list (File. "/"))?

9:08 btw, how do I get a sequence of all namespaces that are currently loaded?

9:08 chouser: AWizzArd: all-ns

9:08 AWizzArd: ah right

9:08 ambient: why?

9:10 chouser: adityo: (for [f (file-seq (java.io.File. ".")) :when (.isFile f)] ...)

9:35 ambient: AWizzArd so i dont have to do (bit-shift-left 2 32) or (int (Math/pow 2 32)) all the time

9:36 (.start (Thread. foo-bar)) seems to block. how do i get a non-blocking thread?

9:36 from the REPL

9:37 chouser: that doesn't block the current thread

9:38 ambient: yes

9:39 my code currently looks like this: http://paste.pocoo.org/show/146866/

9:39 the intention is to call (eng-start) from the REPL, then after (eng-stop)

9:40 waiit.. perhaps i need to give a fn to the Thread.

9:40 chouser: yes you do.

9:40 ambient: hah! :P

9:40 thanks

9:40 chouser: btw, don't use 'def' inside a 'defn' like that.

9:41 'def' does not make a local

9:41 ambient: i know

9:41 but (def dl (atom (audiochan-open 44000))) does IO which I don't want to happen until (eng-start)

9:42 chouser: then do (def dl (atom nil)) at the top level, and (reset! dl (audio-chan-open 44000)) in the fn

9:42 ambient: ok

9:48 this is a bit embarassing how much functionality i can pack into so little amount of lines :/

9:52 heh, i now have a fully functioning FM synthesizer from the REPL :p

9:52 now just to connect midi-input

9:52 rhickey: ambient: cool!

9:52 ambient: thanks :)

9:55 * rhickey wrote midi software way back

9:56 AWizzArd: ambient: can you play the piano in the repl? :)

9:56 ambient: not yet

9:56 rhickey: http://emusician.com/images/archive/backissues85-90.html EM March 1988 REVIEWS: Savant Audio Edit-8000 (mine)

9:56 ambient: i need to do envelope-generator that's triggered by the midi

9:59 AWizzArd: oh, 20 years og

9:59 ago

10:00 rhickey: I should have said waaay back :)

10:01 chouser: I may have been transitioning from QuickBasic to Pascal around then

10:02 AWizzArd: progress :)

10:03 chouser: "Desk accessory to load patch files available free via BBS"

10:03 AWizzArd: does the new branch now have everything from master (and more, like defclass*)?

10:07 rhickey: http://www.atarimagazines.com/st-log/issue29/08-1_ST_NEWS_KORG_DSS-1_EDITING_SOFTWARE.php

10:07 AWizzArd: cute

10:08 rhickey: "but it does require one megabyte of RAM" :)

10:08 dreish: But, the Amiga had more colors and was therefore better!

10:08 ambient: atari had a midi-port built-in

10:08 :)

10:09 the times when normal computer magazines had articles like "how to program your C64 to read data from weather satellite"

11:53 lambdatronic: howdy folks. I've just run into something that just threw me a bit, and I'm looking for the rationale (or if this is a bug).

11:54 I'm currently using Clojure 1.0.1-alpha-SNAPSHOT, and (= [] ()) and therefore (isa? [] ()) returns true.

11:55 (isa? () []) also returns true.

11:56 however, none of the other empty collection values are equivalent [i.e. (isa? () {}) (isa? () #{}) (isa? [] {}) (isa? [] #{}) (isa? {} #{}) (isa? {} []) (isa? {} ()) (isa? #{} ()) (isa? #{} []) (isa? #{} {})]

11:56 So what gives?

11:57 rhickey: lambdatronic: isa? is not about instances, it's about types, so don't confuse with instance? or =

11:57 when used with aggregates (i.e. vectors), it is about aggregates of types

11:57 lambdatronic: however, isa? performs = first before traversing type hierarchies.

11:58 rhickey: (isa? [String String] [Object Object])

11:58 lambdatronic: and its (= () []) that's throwing this all off.

11:58 the = fails on all the other sentinel values as well.

11:59 rhickey: (isa? {} []) is not meaningful

11:59 they are not types not aggregates of types

11:59 the only supported aggregate is a vector of types/tags

12:00 lambdatronic: When would I see this in use? (and this still doesn't get at the heart of my question, which is why does (= () []) return true?)

12:01 Chousuke: an empty list is structurally equivalent to an empty vector, I suppose.

12:01 rhickey: lambdatronic: that's a different question having nothing to do with isa? - = on collections divides collections into families - sequential, map, set - members of the same family with the same contents compare =, otherwise equality would have extreme type brittleness

12:03 (and (sequential? []) (sequential? ())) -> true

12:03 lambdatronic: hmm...but {} and [] don't compare equal although the key/val mapping functions both work on them.

12:04 rhickey: right, there will always be overlap in behaviors of collections, sequential/map/set is just one way to separate them

12:04 a vector is not a full map, even though it is somewhat associative

12:05 lambdatronic: alright, but = always follows this particular rule, so of the four underlying collection type, vectors and lists are lumped together while the others remain separate.

12:06 rhickey: the whole phrase 'underlying collection type' implies a lumping already, i.e. sorted and hashed sets, many flavors of maps

12:08 lambdatronic: right, I got that. But given the way the language documentation stands, those lumpings were already presented as being pretty intuitive. saying that lists and vectors are = if their contents are equal just crosses a boundary in my mind that comparing array-maps and struct-maps wasn't likely to.

12:08 but now I know, I guess, and knowing is the half the battle.

12:08 ;)

12:08 rhickey: equality deals with the collection taxonomy at a level where there are 3 lumps, and that matches the lumping that occurs in j.u.Collections as well

12:09 lambdatronic: ah, therein lieth the rationale.

12:09 it's a javaism.

12:11 I see now the other spooky things one can do with this => (= [1 2 3 4] (seq #{1 2 3 4}))

12:11 or (= '([1 2] [3 4]) (seq {1 2 3 4}))

12:12 rhickey: lambdatronic: no, it is not a Javaism, it was there before they were aligned. I think there's more utility to sequential equality than separating the two

12:13 lambdatronic: yeah, I'm seeing that rich. hence my last two examples.

12:13 rhickey: the rationale is simply one of at what level is it most useful to use the abstractions, presuming one would never want exact type match included in collection equality

12:13 lambdatronic: that is the presumption, yes.

12:14 it's the one that threw me. I was working through a haskell book and implementing all the exercises in their equivalent clojure, to compare and contrast the language features.

12:14 rhickey: it can be difficult to see the abstraction due to the overlaps, but a lot of the utility in Clojure comes from maximizing the use of the abstractions, i.e. extending to as many cases as makes sense and are efficient

12:15 lambdatronic: I was examining pattern matching, and I noted that a lot of pattern matching is just for destructuring binding (which was easy enough to map to clojure).

12:15 sure enough, dynamicity is the name of the game, after all.

12:16 rhickey: I thought there were some docs on how collection equality worked, but can't find them now...

12:16 lambdatronic: it's when I was looking for a native way to map pattern matching for different argument values that I switched over to multimethods and hit the wall when trying to distinguish between an empty list and an empty vector. hence my question (and its original phrasing with isa?).

12:16 nor can I...

12:16 rhickey: instance? is what you want there

12:17 or the abstraction-blah? predicates

12:17 lambdatronic: you mean like vector?, map?, seq?, list?, set?

12:18 rhickey: yeah:

12:18 user=> (seq? ())

12:18 true

12:18 user=> (seq? [])

12:18 false

12:18 lambdatronic: hmm...sneaky

12:19 so let me ask again quickly about the aggregates of types you were discussing earlier.

12:19 how would I use that with isa?

12:20 is it something like the opportunity to match multiple values?

12:20 rhickey: exactly

12:21 lambdatronic: sorry, I didn't phrase that correctly...too ambiguous

12:21 as in, is this a disjunctive or a conjunctive match?

12:22 rhickey: conjunctive

12:23 since dispatch functions in multimethods can return only a single value, this lets you return a value (vector of types/tags) and have the built in isa? match all

12:24 lambdatronic: so my multimethod dispatch function has to return a sequence of values (which may be anything sequential), and my matching dispatch values will all use a vector to represent them?

12:24 ok

12:25 rhickey: vectors only

12:25 lambdatronic: so why are vectors the only allowed matchable collections?

12:25 rhickey: fast count test

12:25 lambdatronic: hmm

12:27 rhickey: basically, they do the job and adding generatily wil lslow things down, no need here

12:27 * rhickey can't type today, or any day :)

12:28 lambdatronic: no worries, I've got a heuristic lexer/parser in my brain. ;)

12:29 but I see that multimethods will match on maps, sets, etc.

12:29 as in, I just tried it, and it worked.

12:30 so remind me again where the vector-only restriction comes into play? I get the sense I'm missing something important here.

12:30 or just being dense.

12:31 chouser: since you want to compare two collections with different values in them, you need them to be sequential to get sensible results, right? maps and sets don't make sense.

12:32 lambdatronic: chouser: please see 3 posts back.

12:32 chouser: but the position matters.

12:32 lambdatronic: (= {:a :b :c :d} {:c :d :a :b})


12:33 and of course, that works just fine, as expected.

12:33 again, see the post I just made.

12:33 chouser: right, but often you want to check inheritence, not equality

12:34 lambdatronic: so when we're talking about the vector-only matching, we're strictly speaking about the inheritance checking post-equality testing?

12:35 chouser: well -- I'm saying non-sequential things don't even make sense because of that. The restriction to vectors only may be more involved.

12:36 rhickey: lambdatronic: the only collection supported for isa? is vector, and the only reason to pass a vector is that you have more than one type relationship you want to test in a single isa? call. isa? is not instance?

12:36 chouser: (derive ::A ::D) (derive ::B ::C)

12:36 (isa? [::A ::B] [::D ::C]) ;=> true as you'd expect

12:37 (isa? #{::A ::B} #{::D ::C}) ;=> false, because it doesn't really make sense

12:38 lambdatronic: okay, I see your point now.

12:38 it's just helpful with the clojure derive functionality.

12:39 or the java class hierarchy too, of course

12:40 rhickey: isa? is about types/tags - saying (isa? () []) doesn't ask the question, "isa list a vector?', it asks the (unsupported) question, "is each member of this list isa? the corresponding member of the vector?" - being empty means you are not testing anything really

12:41 chouser: addMethod could throw something if given an non-vector collection

12:41 rhickey: isa? isn't bound to multimethods

12:42 chouser: right, but defmethod isn't speed critical like isa?

12:42 lambdatronic: yep, got that, rich. thanks. it was never the deriving part of isa that I was confused about. as I said earlier, what I didn't understand was why the two were =. Since isa? performs = first and I was doing the comparison with multimethods in my code, I just associated the problem with isa? in my first post (though I meant =).

12:43 but you cleared up your rationale for why (= [] ()) is true. so all is well in the world.

12:43 rhickey: chouser: but non vectors aren't wrong, if you want the equality test

12:43 lambdatronic: thanks again, guys. keep on hackin' in the free world. I'm out.

12:45 rhickey: i.e. you could dispatch on sets, vectors just get 'isa-enhanced' equality

12:46 chouser: ah, I see. I didn't realize isa? was explicitly checking for vectors before doing isa? on the items.

12:47 rhickey: that needs better docs I guess

12:48 so it looks like we can do the vast majority of the rest of deftype and defclass on the macro side of things, expanding into defclass* thus far

12:49 the one big sticking point is the unavailability of the class being defined, and the fact that all interop compilation uses reflection and thus needs a Class object...

12:50 and you end up needing the class-being-compiled quite often to avoid reflective calls to: its ctor in copying ops, fields of other instances of the same type, instance? checks, arg hints of same type

12:52 chouser: gotta go buy carving pumpkins. bbl.

13:22 ambient: how can I stop a macro from adding the namespace to the variable? http://paste.pocoo.org/show/146907/

13:23 i need evt and val just as they are, without any namespaces in front of them

13:23 spuz: Does the clojure compiler generate intermediate .java files before the .class files are generated?

13:24 robsynnott: Doubt it; doesn't it generally compile to JVM bytecode, not java?

13:25 spuz: I expect so

13:26 but perhaps there is some way to view the output of the compiler as generated java code...?

13:26 ankou_: hi, what exaclty is the graphical inspector?

13:26 is there an article or something like that? can't find anything about this topic

13:26 spuz: I've tried decompiling the generated .class files but it really doesn't make sense as the code generated wouldn't appear to compile

13:27 ambient: clojure.contrib.swing-utils is a bit useless for me without a tutorial :(

13:32 notallama: ambient: ` adds namespace, ' doesn't. so you can unquote something and requote it like `(blah blah ~'x blah blah)

13:33 ambient: aha :)

13:34 chouser: spuz: Clojure compiles directly to bytecode that can in many cases not be represented correctly as .java

13:34 spuz: chouser: heh, thought as much :p

13:35 somnium: anyone tried using jad or similar on clojure's .class files?

13:37 chouser: ankou_: (require 'clojure.inspector) (clojure.inspector/inspect-tree {:a 1 :b {:c 2 :d 3}})

13:43 spuz: somnium: I've tried JD-GUI: http://java.decompiler.free.fr/?q=jdgui

13:43 sometimes it gives useful results

13:44 in my case though it seems the body of the function I'm looking at does absolutely nothing!

13:51 AWizzArd: ~seen kotarak

13:51 hiredman: bot gone?

13:53 chouser: rhickey: even if interop didn't use reflection, but instead examined .jar and .class files, that wouldn't help avoid reflective calls to defclass* classes.

13:59 right? so interop using reflection but sharing a classloader for a whole file might be closer to the right answer?

14:22 spuz: I'm still not really sure what the difference is between a closure and an anonymous function. Can someone explain what this example would do if Clojure did not support closures? http://lispwannabe.wordpress.com/2008/10/24/closures-in-clojure/

14:25 rys: the closure closes over state

14:25 The anonymous function is just that

14:26 It's a function with no ident

14:26 chouser: spuz: without closures, 'x' would not be defined in (fn [y] (+ x y))

14:27 spuz: chouser: so you would get an error saying "x not defined in this context"?

14:27 toups: Is there something like doseq but which executes in parallel? I have a body for which has side effects (writes to files) but not to any of the same files for a given element of the seq, so I should be able to parallelize it trivially.

14:28 Chousuke: use pmap with dorun

14:28 chouser: spuz: right

14:29 toups: (dorun (pmap (fn ...) sq))?

14:30 Chousuke: like th at?

14:30 Chousuke: yeah

14:30 toups: Thanks

14:30 Chousuke: spuz: anonymous functions and closures are orthogonal concepts. a named function can form a closure too.

14:31 AWizzArd: spuz: you have a function F with a parameter vector P and a body B. In B a variable is accessed which is not in P, but also not a global var.

14:31 Chousuke: just do (let [foo bar] (defn ...))

14:31 spuz: I've only ever seen closures using anonymous functions but that makes sense

14:32 AWizzArd: spuz: you can use Closures in non-anon functions as replacement for (Java) classes.

14:32 Chousuke: they're much more common as anonymous functions

14:32 AWizzArd: Imagine you have a Point object, with the members x and y. You want to create a new point, or update one.

14:33 You could have a (let [x 0, y 0] (defn make-point ..) (defn distance ...)) and so on.

14:33 Then make-point and distance adn your other functions would be like methods in a Java class, and x and y are like the fields of the class Point.

14:37 toups: wheee - clojure is pretty fun.

15:03 Qvintvs: does anyone know why I'm getting clojure.lang.PersistentArrayMap cannot be cast to java.lang.Number from this code (line 33): http://pastebin.org/48210

15:04 The-Kenny: Qvintvs: Where in this code?

15:04 Qvintvs: line 33

15:08 The-Kenny: Qvintvs: The problem is in add-to-map called by get-words.

15:08 Qvintvs: Do you really want to emit "words" two times to add-to-map?

15:11 Qvintvs: The-Kenny, ah, thx

15:13 The-Kenny: Qvintvs: I think zou also switched the last two values... v should be a number and not an object.

15:13 s/zou/you/

15:13 Qvintvs: The-Kenny, ya, i noticed that too

15:57 hiredman: clojurebot: ping?

15:57 clojurebot: PONG!

15:57 somnium: ,(#(%) #(+ 2 3))

15:57 clojurebot: 5

15:58 somnium: hiredman: you turned off the I-Ching?

15:58 hiredman: (+ 1 4)

15:58 clojurebot: *suffusion of yellow*

15:59 somnium: oh good

16:05 ,(doc rfirst)

16:05 clojurebot: Excuse me?

16:06 somnium: some functions on the cheatsheet http://clojure.org/cheatsheet don't seem to be there

16:08 hiredman: the cheatsheat is kind of out of date

16:08 ,(doc nfirst)

16:08 clojurebot: "([x]); Same as (next (first x))"

16:09 somnium: is that what rfirst did, or was it (rest (first x))?

16:10 licoresse: IMO, look at http://www.daimi.au.dk/~eernst/dPersp08/cheatsheet.pdf for what I think clojure.org needs

16:11 there was a similar "terse guide to Smalltalk", but I cannot find it anylonger

16:11 somnium: yeah, that would be nice, python has some good ones too

16:12 makes it easy for anyone to get started

16:13 licoresse: ah, found it:

16:13 that one helped me a lot when I was beginning squeaking

16:14 hircus: man, Clojure maps are *fast* -- http://hircus.wordpress.com/2009/10/25/mini-kanren-benchmarking-different-substitution-data-structures/

16:15 rhickey: any chance we could get IMapEntry's getter renamed to value() ?

16:16 somnium: licoresse: how did you learn to like the squeak gui?

16:17 licoresse: I didn't

16:17 but when you have turtles all the way down

16:17 you learn to like anything

16:17 !!

16:17 so I was in love for a couple of years

16:17 somnium: licoresse: too bad there's no emacs mode with buffers instead of windows

16:18 danlei: pharo looks a lot nicer than the vanilla squeak images imho

16:18 licoresse: somnium: you mean workspaces?

16:18 the problem with squeak as many other similar things is that they have their own ecosystem

16:19 and integrate poorly to the rest of the world

16:20 danlei: I'd love to have something like squeak/pharo for lisp. I ran medley in a VM (like genera, but for InterLisp), but it's quite aged ...

16:21 it still is a nice environment though

16:21 licoresse: well, I am happy to admit that Clojure is my new love now

16:21 somnium: I think if I had found smalltalk before I learned emacs I would have liked it, but when I tried it was already too unbearable to get started

16:21 licoresse: I only wish someone would do a proper debugger thing in emacs

16:21 danlei: somnium: I know what you mean :)

16:22 licoresse: somnium: it's not so much the language, which is fine, but more the environment

16:23 the concepts of do-its, print-its etc

16:23 and that brilliant debugger

16:23 danlei: for cl, the inspector and debugger are actually quite nice, don't get in your way

16:23 (slime)

16:24 licoresse: danlei: but none of that is avail to clojure, is it?

16:24 danlei: no, not that i'm aware of

16:28 somnium: 'show and 'source in repl-utils do most of what I want for insepcting, but I don't what the CL inspector does

16:28 notallama: pointfree stuff is coming along nicely. i should probably do my homework, though :V http://github.com/hclarke/pointfree-clojure

16:29 danlei: somnium: there are restarts, eval-in-frame, goto-source ...

16:29 hiredman: oooo

16:29 danlei: somnium: you can eval code in a stack frame an restart it, for example

16:29 *and

16:30 somnium: notallama: that looks nice, I was lamenting the lack of something like your &&& and *** just yesterday

16:30 djork: oh man I would kill for a Squeak-like debugger in Clojure

16:31 actually I just want Clojure errors instead of Java errors

16:31 stack traces tha tis

16:31 licoresse: djork: that would help

16:32 or that the *slime-messages* buffer scrolls correctly

16:32 djork: heh yes that too

16:32 hiredman: have you tried out clojure.stacktrace?

16:32 somnium: my favorite is 'no message', java null pointer, no source

16:32 licoresse: guess that is an easy thing to "fix"

16:33 hiredman: no, I have not

16:33 anyone written about it, a blog or something?

16:34 hiredman: nope

16:34 I only found it because my reader was barfing on it while I was using it to build clojure

16:34 djork: hah

16:35 licoresse: ooo

16:35 http://img.skitch.com/20090721-efy2e4wgsrhxs2cxsbnu4c4ftx.png

16:36 somnium: isn't that what slime does?

16:36 licoresse: sans colors

16:36 somnium: true

16:37 robsynnott: ooh, pretty

16:38 djork: wow, nice

16:38 slime doesn't look like that for me

16:39 1: user$eval__6140.invoke(NO_SOURCE_FILE:1)

16:39 oh duh

16:39 nevermind

16:41 danlei: http://danlei.nfshost.com/sldb.png

16:41 that would be nice to have in clojure too

16:42 somnium: wow

16:42 I hope something like that is in the works somehow or other

16:42 danlei: and that's just the top of the iceberg

16:43 well,

16:43 the problem is, that for example "restart" are a feature of the cl condition system

16:43 it's not a slime thing per se ...

16:43 Chousuke: the JVM just has exceptions :/

16:43 licoresse: 'clojure.stacktrace is actually quite nice

16:44 just need to connect it properly to the 'slime-compilation-finished-hook

16:44 danlei: in short: there are conditions, handlers, and restarts. somewhere, a condition gets signalled, then, if a handler handles it, a restart is invoked. the restart is usually down the stack, the handler up the stack ...

16:45 if no handler handles a condition, it will be handled by a human, in the debugger

16:45 Chousuke: I wonder what it would require for Clojure to emulate the condition system.

16:45 somnium: licoresse: could you paste the .emacs line you used?

16:45 Chousuke: there's error-kit but... hm.

16:46 licoresse: somnium: it's just a (add-hook 'clime-compilation-finished-hook 'whatever-you-like)

16:46 slime (not clime)

16:46 somnium: licoresse: so just 'clojure.stacktrace there?

16:46 licoresse: no no

16:46 you need to call swank

16:47 or send something to the swank process or whatever

16:47 I am not completely understanding this yet

16:47 somnium: licoresse: ah, I thougt you had it hooked up already

16:47 licoresse: :-(

16:48 Chousuke: or you can bug technomancy to add it to swank-clojure next time he joins :P

16:48 somnium: licoresse: I've been putting off reading swank-clojure.el

16:48 licoresse: anyway, I think that the above-mentioned hook is only called when the compilation is successful, I have to test it more

16:49 Chousuke: it shouldn't be too difficult to conditionally enhance the repl if contrib is available.

16:49 licoresse: I lost the link, there was someone mentioning clojure in emacs

16:50 like, extending elisp with clojure stuff

16:50 somnium: swank-clojure.el is a mess

16:51 I guess that is what you get when everything is global

16:51 somnium: licoresse: I know, I looked at it once :)

16:51 Licenser: ow a lot is going on here

16:52 somnium: I think I like it best as a black box

16:52 licoresse: heh

16:54 wait a minute, I don't mean the swank-clojure.el is a mess, it's just a mess to my eyes - I am sure it's brilliant in it's own way ;-)

16:55 it's just 250 lines long

16:55 somnium: I'm sure it makes perfect sense once it makes sense to you

16:57 hiredman: http://www.thelastcitadel.com/images/syntax.png this is a mess

16:57 somnium: heh

16:57 licoresse: hehe

16:58 is that object oriented?? :D

16:58 hiredman: I spent a large chunk of yesterday tracing that out

16:58 somnium: I like in once of rich's presentations he had one of those with "There Will Be A Quiz!" in big letters

16:59 hiredman: that is the syntaxQuote method from SyntaxQuoteReader in clojure.lang.LispReader

16:59 that is all in one method

16:59 somnium: good god

16:59 licoresse: ouch

16:59 hiredman: once I made the graph it made sense, but before that :(

17:01 somnium: hiredman: it reminds me of the inside of a neglected server

17:02 licoresse: actually most of it makes sense, it's just that when you graph it...

17:02 somnium: http://www.michaelaulia.com/blogs/wp-content/uploads/2009/10/messy-cable-solution.png

17:03 licoresse: hmm

17:08 Chousuke: hiredman: I think the worst part of implementing syntax-quote is the symbol resolution :P

17:10 licoresse: hehe, reading about CIP (Clojure Idiomatic Police)...

17:10 hiredman: we have those?

17:10 Chousuke: http://github.com/Chousuke/clojure/blob/sq-macro/src/clj/clojure/core.clj#L562 I'm still not sure this is right.

17:11 also I wonder why there is no syntax-highlighting :/

17:12 hiredman: the graph really helped me understand the flow

17:14 I have five places where my reader still relies on LispReader: ReaderException, FnReader, ArgReader, EvalReader, and readDelimitedList

17:14 Chousuke: !

17:14 I might just have figured out the bug I have compiling Clojure with my reader.

17:15 epiphany out of nowhere

17:15 hiredman: huzzah!

17:15 licoresse: how wonderful!

17:15 Chousuke: now I hope I'm right.

17:17 notallama: is there a way to not have to type the classname for java static functions? like (sin x) instead of (Math/sin x) ? or do i just have to def the ones i want to something shorter?

17:17 Chousuke: contrib has static-import I think. maybe that would help?

17:21 somnium: does (into {} ...) always create an ArrayMap regardless of number of args?

17:21 Chousuke: ,(class (into {} [1 2]))

17:21 clojurebot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: Integer

17:22 Chousuke: ... ?

17:22 ah

17:22 ,(class (into {} [[1 2]]))

17:22 clojurebot: clojure.lang.PersistentArrayMap

17:23 Chousuke: hmm.

17:23 ,(class (into {} (take 15 (repeatedly [1 2])))

17:23 clojurebot: EOF while reading

17:23 Chousuke: ,(class (into {} (take 15 (repeatedly [1 2]))))

17:23 clojurebot: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.IllegalArgumentException: Wrong number of args passed to: PersistentVector

17:23 notallama: Chousuke: yes, that is exactly what i needed. thanks! (it's called import-static)

17:23 Chousuke: ,(class (into {} (take 15 (repeat [1 2]))))

17:23 clojurebot: clojure.lang.PersistentArrayMap

17:23 somnium: ,(class (into {} (interleave (range 100) (range 100))))

17:23 clojurebot: java.lang.IllegalArgumentException: Don't know how to create ISeq from: Integer

17:23 Chousuke: ,(class (into {} (take 50 (repeat [1 2]))))

17:23 clojurebot: clojure.lang.PersistentArrayMap

17:24 Chousuke: apparently :/

17:24 somnium: hmm

17:24 Chousuke: ,(class (into {} (take 5000 (repeat [1 2]))))

17:24 clojurebot: clojure.lang.PersistentArrayMap

17:24 Chousuke: ...

17:24 somnium: well, on the bright side, that means I have some very easy optimizations to implement :)

17:24 Chousuke: sorry, I'm stupid :D

17:24 all those maps had only one element.

17:24 hiredman: haha

17:24 Chousuke: should go to sleep.

17:25 somnium: ,(class (into {} (partition 2 (interleave (range 100) (range 100)))))

17:25 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.util.Map$Entry

17:25 hiredman: ,(class (into {} (map vector (range 100) (range 100))))

17:25 clojurebot: clojure.lang.PersistentHashMap

17:25 somnium: ah

17:25 well, that solves that

17:32 (conj {} [1 2])

17:32 ,(conj {} [1 2])

17:32 clojurebot: {1 2}

17:32 div: hiredman: you should consider spending an hour or 2 playing with graphviz nxt time you need to graph something like http://www.thelastcitadel.com/images/syntax.png

17:32 somnium: ,(conj {} '(1 2))

17:32 clojurebot: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.util.Map$Entry

17:33 hiredman: div: that is graphviz

17:33 div: what's with the scary lines :)

17:34 the boxes are familiar yes, but it just seems like you drew the connections with paint :p

17:34 hiredman: the dark arrows are control flow and the thin lines are, uh?, state flow?

17:34 nah, it's all dot

17:35 div: i see

17:36 somnium: hmm, I guess (into {} '(:foo :bar)) isn't supported for performance reasons?

17:37 hiredman: eh?

17:37 where are the keys and values?

17:38 somnium: it seems to be because lists don't implement IEditableCollection

17:38 but [:foo :bar] does

17:38 so that was the basis for my guess

17:39 hiredman: no

17:40 somnium: er, scratch that, re-reading into

17:40 hiredman: (into {} [:foo :bar]) and (into {} '(:foo :bar)) both won't work

17:40 somnium: I know

17:40 hiredman: (into {} '([:foo :bar])) does work

17:41 somnium: hmm

17:41 hiredman: (conj {} :foo :bar) doesn't work

17:41 (conj {} [:foo :bar]) does

17:46 AWizzArd: though i find (assoc {} :foo :bar) documents the code better

17:47 hiredman: sure

17:47 I'm not advocating conj over assoc for associative things, I am just trying to illustrate why '(:foo :bar) does not work and '([:foo :bar]) does in into

17:48 AWizzArd: yes

17:51 Licenser: somnium: how is the mongodb driver going?

17:51 somnium: Licenser: a pre-alpha version is on github, its working but test coverage is poor

17:52 Licenser: wooh

17:52 somnium: Licenser: would be happy if you give it a try and let me know how it goes

17:52 been writing tests this afternoon

17:52 Licenser: somnium: I'm planing on it ;)

17:53 somnium: how is it named?

17:54 hiredman: clojurebot: how is it named?

17:54 clojurebot: with style and grace

17:55 Licenser: ah found it

17:56 somnium: I considered mongojure and clomongo but they didn't appeal

17:56 Licenser: hah I tried mongojure :P

17:57 somnium: maybe 'clongo wouldn't be so bad

17:58 piccolino: somnium, so cool. I was just a week ago wishing there was a MongoDB driver for clojure taht worked like this.

17:59 somnium: piccolino: pre-alpha! :) please, let me know what breaks, I've a lot of improvements in mind, and it wasn't test-driven, more like repl-hacked

18:00 hiredman: sorry I'm being slow about this, how does the line in the source of conj ([coll x] (. clojure.lang.RT (conj coll x)) work ?

18:02 Licenser: somnium: I'm excited over your driver :P

18:02 hiredman: it's a call to the conj static method on RT

18:03 anway, conj on maps takes a key-value pair

18:03 '([:key :value]) is a sequence containg a key-value pair

18:04 '(:foo :bar) is not

18:04 somnium: hiredman: ok, been putting off reading the .java portion of clojure, thanks

18:05 hiredman: somnium: you don't need to

18:06 the point is '(:foo :bar :baz :bleep) is a flat sequence, '([:foo :bar] [:baz :bleep]) is a sequence of two element vectors

18:07 somnium: hiredman: right, but (list (list 1 2) (list 2 3)) also doesn't work, which is a sequence of two element sequences, or no?

18:07 hiredman: the first will not work because a. into uses conj (or did last time I checked) and b. it contains no key/value groupings

18:07 somnium: so I assume it has to do with how conj works

18:07 hiredman: that is because conj for maps takes a map entry, and two element vectors are map entries

18:08 ,(class (first {:a :b}))

18:08 clojurebot: clojure.lang.MapEntry

18:08 hiredman: ,(first {:a :b})

18:08 clojurebot: [:a :b]

18:10 somnium: hiredman: ah, now it clicked, I wasn't thinking about the definition of map entries

18:24 hiredman: interesting trivia, (eval (eval (quote (list + 1 2 3)))) calls the reader to read (X.) where X is the name of the class the + fn is compiled to

18:24 LauJensen: ~seen jdz

18:24 clojurebot: no, I have not seen jdz

18:30 Licenser: somnium: from the docs your API looks very neat

18:32 somnium: Licenser: it can still be improved, I'd like to completely suppress the class hierarchy defined by the java-api, but that will negatively impact performance for mass operations

18:33 Licenser: hmmm

18:34 somnium: Licenser: hopefully I'll get the core test suite finished this evening

18:34 Licenser: I have a request so :P fetch-one-with-defaults that would be very sweet

18:34 s

18:34 i

18:34 since in the KV store you never can know what you get

18:34 somnium: Licenser: how would that work?

18:34 Licenser: well like:

18:35 (fetch-one-with-defaults :robots :where {:name 'rodney'} :defaults {:type 'killer robot with laser eyes'})

18:36 so it either returns {:name 'rodney' :type 'a cute little robot kitten'} or if rodney had no type {:name 'rodney' :type 'killer robot with laser eyes'}

18:36 hiredman: watch the single quotes

18:36 somnium: ah

18:36 Licenser: since I don't think mongodb allows field defaults as it has no scemes

18:36 hiredman: thanks

18:37 piccolino: Does it work with hierarchical objects?

18:37 Licenser: piccolino: it does not work at all :P it's a dream of mien

18:37 piccolino: Sorry, I was asking somnium about the main functionality. :)

18:38 I see that map-to-object just calls the mongo-java function, not sure how that one works yet.

18:38 somnium: piccolino: the core api is all json, so anything you can write in json you should be aple to express with a POCM (plain old clojure map)

18:39 or BSON I guess, but whatever, the structure is just like JSON

18:39 piccolino: So if I put a clojure map in a clojure map, the Java API will correctly structure that?

18:39 AWizzArd: yes

18:39 piccolino: Cool.

18:40 AWizzArd: you can also use the json parser in Clojure Contrib.

18:42 somnium: piccolino: they mongodb-java-driver also has a JSON/parse method that creates mongo objects, will probably wrap that in the next release

18:43 piccolino: but for the most part my goal was to create an illusion that youre using a DB that just knows how to speak clojure

18:43 piccolino: Totally, that's how it should be.

18:47 I just guess the Java MongoDB driver had more reflection than I realized.

18:48 ankou_: hi, is there a simple search function like (first (filter x y)) but more efficient?

18:49 somnium: piccolino: far off in the future there could be a low level driver that does BSON to clojure, in the near future I want something easy and not broken to use for my own projects :)

18:49 piccolino: What would be the advantage of that?

18:49 somnium: piccolino: speed most likely

18:50 ankou_: try (some x y)

18:50 hiredman: some returns the result of the predicate

18:51 ankou_: which is true and not the element itself

18:52 hiredman: ankou_: what is the problem with (first (filter ...))

18:53 ankou_: well I thought that even if it uses a lazy sequence it might be slower then a real (convenient) find function or am I wrong?

18:54 somnium: ,(some #(if (string? %) % nil) '(:foo :bar "yes" :wow))

18:54 clojurebot: "yes"

18:54 somnium: though I don't suppose that's better than (first (filter ...))

18:56 hiredman: ankou_: unless the input is sorted you are going to have to do a linear search, which is exactly what (comp first filter) does

18:58 somnium: ,(time (first (filter #(= 2000 %) (iterate inc 1))))

18:58 clojurebot: 2000

18:58 "Elapsed time: 13.013 msecs"

18:59 somnium: ,(time (some #(if-let [x (= 2000 %)] x) (iterate inc 1)))

18:59 clojurebot: true

18:59 "Elapsed time: 9.003 msecs"

18:59 somnium: bah

19:00 ,(time (some #(if (= 2000 %) %) (iterate inc 1)))

19:00 hiredman: ,(time (some #{2000} (iterate inc 1)))

19:00 clojurebot: 2000

19:00 "Elapsed time: 11.467 msecs"

19:00 somnium: nice, I don't use sets nearly often enough

19:02 ,(time (first (filter #(= 100000 %) (iterate inc 1))))

19:02 clojurebot: 100000

19:02 "Elapsed time: 383.559 msecs"

19:02 somnium: ,(time (some #(if (= 100000 %) %) (iterate inc 1)))

19:02 clojurebot: 100000

19:03 "Elapsed time: 168.427 msecs"

19:04 somnium: (time ((comp first filter) #(= 100000 %) (iterate inc 1)))

19:04 ,(time ((comp first filter) #(if (= 100000 %) %) (iterate inc 1)))

19:04 clojurebot: 100000

19:04 "Elapsed time: 218.176 msecs"

19:05 somnium: hiredman: internally, how different are (first (filter ...)) (comp first filter) ... and (some ...) ?

19:05 or at all?

19:06 hiredman: (comp first filter) creates a new function

19:07 (first (filter ...)) doesn't

19:07 which means there is an extra function invocation too

19:08 somnium: hmm, some and filter are very different

19:09 hiredman: ~def some

19:09 somnium: why is filter so complicated?

19:09 ataggart: some is the complement of any

19:09 erm

19:09 hiredman: some is not lazy

19:09 filter is

19:10 ataggart: every? not any, sry

19:10 somnium: of course, and filter returns a whole collection, duh

19:11 'some' maybe isn't the best name for what it actually does, 'first-truthy' ?

19:11 hiredman: true for some elements

19:11 some

19:11 ataggart: I like "any?"

19:12 somnium: hiredman: is there any way you could wire up clojurebot to 'source in repl-utils?

19:12 -> (defn some [pred coll] (when (seq coll) (or (pred (first coll)) (recur pred (next coll)))))

19:13 hiredman: ,(use 'clojure.contrib.repl-utils)

19:13 clojurebot: java.lang.ExceptionInInitializerError

19:13 hiredman: clojurebot: same to you!

19:13 clojurebot: It's greek to me.

19:14 danlei: ,(require '[clojure.contrib.repl-utils :as ru])

19:14 clojurebot: java.lang.NoClassDefFoundError: Could not initialize class clojure.contrib.repl_utils__init

19:15 danlei: didn't that use to work?

19:21 hiredman: ,(use 'clojure.contrib.repl-utils)

19:21 clojurebot: nil

19:21 hiredman: ,(source 'some)

19:21 clojurebot: java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol

19:21 hiredman: ,(source some)

19:21 clojurebot: Source not found

19:21 hiredman: :P

19:21 somnium: hiredman: is there anyway you could put the .clj files on his classpath without compromising his sandbox?

19:49 merijn: Do I understand it right that multi-methods are pretty much the same as pattern matching in Haskell, but with an explicit syntax to mark it?

19:51 notallama: they can be. i think it's closer to guards.

19:52 somnium: -> ((f x y z) x y z)

19:53 how does haskell's pattern matching work?

19:56 merijn: somnium: To use a trivial example (sum over a list, where [] is an empty list): "sum [] = 0; sum (x:xs) = x + sum xs" (or alternatively "sum [] = 0; sum list = head list + tail list")

19:56 err.. sum (tail list) in the latter example, of course

19:57 notallama: it's basically a destructuring bind, and you can put literals in it to match against.

19:58 somnium: x:xs = [x & xs] ?

19:59 hiredman: sort of

20:00 notallama: somnium: [[x & xs]], i think

20:00 merijn: somnium: ":" is list concatenation, so (x:xs) is a list with the first element bound as x and the tail bound as xs

20:00 hiredman: some wrote a pattern matching macro

20:00 someone

20:00 ~matches

20:00 clojurebot: excusez-moi

20:01 hiredman: ~google clojure pattern matching

20:01 clojurebot: First, out of 1630 results is:

20:01 brool » Pattern Matching In Clojure

20:01 http://www.brool.com/index.php/pattern-matching-in-clojure

20:01 somnium: hiredman: ooh, I was thinking about writing one yesterday

20:02 merijn: hiredman: Well, the point wasn't so much how to do pattern matching but if I could compare multi-methods to pattern matching in Haskell.

20:03 somnium: (doc match)

20:03 clojurebot: "clojure.contrib.types/match;[[value & clauses]]; Given a value and a list of template-expr clauses, evaluate the first expr whose template matches the value. There are four kinds of templates: 1) Lists of the form (tag x1 x2 ...) match instances of types whose constructor has the same form as the list. 2) Quoted lists of the form '(x1 x2 ...) match lists of the same length. 3) Vectors of the form [x1 x2 ...] match vector

20:03 notallama: merijn: multi-methods are more general. they dispatch on any function of the arguments you can think of.

20:04 somnium: are there any code examples for contrib.macros/macro-utils ? in the wild or elsewhere ?

20:04 hiredman: nice

20:04 matching on constructor forms is great

20:04 notallama: so, it could choose a method by type, or by value, or by length of a string, or whatever.

20:05 somnium: I really wish there was a cheatsheet for contrib, I keep finding stuff I didn't know was thre

20:05 merijn: notallama: ok

20:19 Licenser: wow the mongodb community is quite fun

20:22 somnium: Licenser: ?

20:23 Licenser: somnium: yap, I just asked a question and ran into a bug, they are very helpfull in the channel :P

21:20 tomoj: technomancy: do you happen to know who maintains elpa gist.el?

23:12 technomancy: tomoj: no, sorry

23:21 lisppaste8: djork pasted "why does this throw a NPE?" at http://paste.lisp.org/display/89274

23:22 djork: If anybody can explain this mysterious error to me, I'd appreciate it.

23:22 hiredman: ,(first '())

23:22 clojurebot: nil

23:22 djork: ah

23:22 ,(dec nil)

23:22 hiredman: ,(dec (first '()))

23:22 clojurebot: java.lang.NullPointerException

23:22 java.lang.NullPointerException

23:22 djork: :)

23:23 thanks

23:23 by the way, iterate is a brilliant thing

23:24 I love the fact that I can just do (nth (iterate next-day [5]) 1234)

23:24 brilliant stuff

23:24 of course my algo. here is not going to work (stack overflow)

23:26 what's the best way to put conj and recur together so that I have a tail-recursion going on?

23:58 chouser: djork: walking a lazy seq shouldn't overflow the stack

Logging service provided by n01se.net