#clojure logs

2009-10-25

00:51qedhow do you compare to strings
00:51qedlike (= str str)
00:51qedor (== str str)
01:04danlarkin(doc =)
01:04danlarkin(doc ==)
01:04scottjqed, =
01:21defnHow do I do a decrementing while loop in clojure?
01:22defnI'm taking some input to this function, an integer
01:22defnI want to decrement that integer until a function on the same input is true
01:22defnand return that integer
01:26lisppaste8cema pasted "md5" at http://paste.lisp.org/display/89237
01:29Guest16869defn: for example like this: (defn foo [n] (if (<= n 3) n (recur (dec n))))
01:30defndanlei: what about with true/false?
01:30danleiwhat do you mean?
01:32defndanlei: http://pastie.org/private/dg1vj8nxhvmk00hjw0jpg
01:32defnthat first function, reverse-and-test is testing to see if the input and the reverse of the input are equal
01:32defnit takes an int
01:33defnin test-down we want to sart at 998001, and decrement that number until we find a palindrome
01:33defndanlei: does that make sense?
01:36danleidefn: (defn palindromep [n]
01:36danlei (= n (read-string (apply str (reverse (str n))))))
01:36danleidefn: if you use that instead of (<= n 3) in the example above, it'll work
01:36danleidon't know if it's elegant, I just followed the string-reversion approach
01:37danlei(defn foo [n] (if (palindrome? n) n (recur (dec n)))) [untested]
01:39defnstring-reversion approach?
01:39danleinumber -> string -> reverse -> number
01:39defnare you a Haskell guy?
01:40defnthe '->'s make me suspicious
01:40danleino :)
01:42defnthat doesn't work
01:42danlei(palindrome? 11) true
01:42danlei(palindrome? 12) false
01:42danleiwhat shouldn't work there?
01:43defnthat works fine
01:43danlei(defn find-palindrome [n]
01:43danlei (if (palindrome? n)
01:43danlei n
01:43danlei (recur (dec n))))
01:44defnbut 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
01:44danlei(find-palindrome 15)
01:44danlei11
01:44danleiI don't see the problem, can you elaborate?
01:44danleior, if you don't like recur ...
01:45danlei(first (drop-while #(not palindrome? %) (iterate dec 998001))) [untested]
01:46defnjava.lang.NumberFormatException: Invalid number: 000899
01:46defn
01:46danleiah, ok
01:46danleiwrap it in a try block
01:46danleinot elegant, but should do
01:46defnthis started out so pretty
01:47defnand now is descending into a pool of liquid shit
01:47defnlol
01:49danleior just use Integer/parseInt instead of read
01:54danleidefn: btw. I tested it and it found the number without any problems
01:55danlei(without changing anything)
01:55qedeven from 998001
01:55qed?
01:56qedoopa
01:56defneven from 998001?
01:57danleiwith parseInt: (defn palindrome? [n]
01:57danlei (= n (Integer/parseInt (apply str (reverse (str n))))))
01:57danlei(first (drop-while #(not (palindrome? %)) (iterate dec 998001)))
02:03defnthanks
02:04danleinot without changing anything tough: forgot () around (palindrome? %) above
02:08danleidefn: this is better: (first (filter palindrome? (iterate dec 998001)))
02:08defnnice filter
02:08defnthanks
02:09danleiwelcome
02:12defndanlei: could you explain how (let [products (for [a (range 100 1000) b (range 100 a)] (* a b))] (reduce max (filter palindrome? products))) works?
02:12defnI don't understand the [ [ []]] stuff within the let, nor how it is passed forward to the reduce max fn
02:13qedim still here
02:13qedfwiw
02:22danleidefn: (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
02:24danleidefn: 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] ...
02:25danleiwhere in [x y] x is out of [a b] and y is out of [c d]
04:37yasonIn an agent action, how do I know which agent was it sent to?
04:38yasonIf 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.
04:48cgrandyason: *agent*
04:48cgrandis bind to the current running agent
04:53yasoncgrand: I saw that and I think I tried that; perhaps I'll cross-check my experiments. Was it documented somewhere?
04:54hiredmanit is
04:55hiredmanalso documented is the fact that agents hold sends until the completion of an action
04:56yasonThe docstring for *agent* is there, perhaps I just didn't find it on the Clojure website.
04:56cgrandyason: http://clojure.org/api#toc9
04:56yasoncgrand: of course, thanks!
04:56cgrandbut no mention of it on clojure.org/agents
04:57yasoncgrand: would've helped if it had been mentioned on the Agents page :)
06:18ambientthreads are still completely controlled with Java interop, right?
06:18ambientand the message passing between threads
06:32Chousukeambient: you can use any of the clojure concurrency constructs instead of using threads directly
06:33Chousukebut yeah, if you do need full control for some reason, it's done via Java interop.
06:33ambientbut if i need to run high-performance computing in the background and send and receive messages from and to that "engine"?
06:34ambientwhat would be the best way to do this with clojure?
06:35ambient(not HPC, just fast math)
06:36Chousukehmm.
06:37ambientthe point is to control it from REPL like this: (start-engine) (send-stuff some-stuff) (stop-engine)
06:37Chousukewell, you might be able to use watchers.
06:37Chousukeand an agent for serialising the message sends
06:38ambientok, going to check out watchers
06:39ambientthe engine might run with IO call-back thread
06:39ambientminus thread
06:40ambientbasically 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
06:40ambientor changes some values in the engine
06:41ambientif it got no inputs, it just generates and plays silence
06:41ChousukeI guess you should just use plain threads.
06:55AWizzArdIs it only me, or do you also see http://github.com/richhickey/ as pretty empty?
06:55ambientAWizzArd only you
06:55AWizzArdah ok, website is back
06:55ambientdepending of your definition of empty
06:56AWizzArdgot a 404, nginx
06:56ambientk
06:56ambienthttp://downforeveryoneorjustme.com/ is pretty useful site
07:57ambientanyone 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)
08:16ambientif i have (def src foo) somewhere else and then try (let [src bar] ...) it gives an error?
08:17AWizzArdno
08:18AWizzArdYou shadow the def'ed src with your let, but this throws no error.
08:18ambientif 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?
08:19ambientwhat is weird that i don't have "src" anywhere in my code
08:19AWizzArdThat could throw an error, because src is imported and you try to name something else like that.
08:19ambientit's some reserved variable?
08:19AWizzArdNo
08:20AWizzArddo you know in which package src is?
08:21ambienthmm, (ns (:use)) doesn't seem to inherit the uses
08:21ambientamb.synth.audiochan > amb.synth.engine > amb.synth.audioloop => audioloop can't find audiochan
08:22ambientso perhaps all the error were caused by leftovers in the SLIME environment
08:25ambientyep
08:29AWizzArdyou started a fresh jvm?
08:29ambientyes
08:40adityohello
08:40AWizzArdHi Adi
08:42adityohey AwizzArd :)
08:43adityoim trying to traverse a directory tree , get something from each file
08:43ambientclojure really needs a native power function :/
08:43adityo(for [file (file-seq (File. "dir"))])
08:44adityoyet i get an error FileNotFoundException (is a directory)
08:48spuzDoes anyone know what this error means? "java.lang.IllegalArgumentException: recur arg for primitive local: x must be matching primitive"
08:52spuzThis seems to happen when I try to cast a local variable to a primitive type inside a 'loop' definition
09:01chouserspuz: you need to make sure that the matching arg in the 'recur' is also primitive
09:04spuzchouser: if I say (let x 2.0), is x not a primitive?
09:04spuzor (let [x 2.0]) even
09:05chouserspuz: right, literal numbers are boxed
09:05chouserso instead try (let [x (double 2.0)])
09:05spuzchouser: ah ok
09:07AWizzArdadityo: did you try (.list (File. "/"))?
09:08AWizzArdbtw, how do I get a sequence of all namespaces that are currently loaded?
09:08chouserAWizzArd: all-ns
09:08AWizzArdah right
09:08AWizzArdambient: why?
09:10chouseradityo: (for [f (file-seq (java.io.File. ".")) :when (.isFile f)] ...)
09:35ambientAWizzArd so i dont have to do (bit-shift-left 2 32) or (int (Math/pow 2 32)) all the time
09:36ambient(.start (Thread. foo-bar)) seems to block. how do i get a non-blocking thread?
09:36ambientfrom the REPL
09:37chouserthat doesn't block the current thread
09:38ambientyes
09:39ambientmy code currently looks like this: http://paste.pocoo.org/show/146866/
09:39ambientthe intention is to call (eng-start) from the REPL, then after (eng-stop)
09:40ambientwaiit.. perhaps i need to give a fn to the Thread.
09:40chouseryes you do.
09:40ambienthah! :P
09:40ambientthanks
09:40chouserbtw, don't use 'def' inside a 'defn' like that.
09:41chouser'def' does not make a local
09:41ambienti know
09:41ambientbut (def dl (atom (audiochan-open 44000))) does IO which I don't want to happen until (eng-start)
09:42chouserthen do (def dl (atom nil)) at the top level, and (reset! dl (audio-chan-open 44000)) in the fn
09:42ambientok
09:48ambientthis is a bit embarassing how much functionality i can pack into so little amount of lines :/
09:52ambientheh, i now have a fully functioning FM synthesizer from the REPL :p
09:52ambientnow just to connect midi-input
09:52rhickeyambient: cool!
09:52ambientthanks :)
09:56AWizzArdambient: can you play the piano in the repl? :)
09:56ambientnot yet
09:56rhickeyhttp://emusician.com/images/archive/backissues85-90.html EM March 1988 REVIEWS: Savant Audio Edit-8000 (mine)
09:56ambienti need to do envelope-generator that's triggered by the midi
09:59AWizzArdoh, 20 years og
09:59AWizzArdago
10:00rhickeyI should have said waaay back :)
10:01chouserI may have been transitioning from QuickBasic to Pascal around then
10:02AWizzArdprogress :)
10:03chouser"Desk accessory to load patch files available free via BBS"
10:03AWizzArddoes the new branch now have everything from master (and more, like defclass*)?
10:07rhickeyhttp://www.atarimagazines.com/st-log/issue29/08-1_ST_NEWS_KORG_DSS-1_EDITING_SOFTWARE.php
10:07AWizzArdcute
10:08rhickey"but it does require one megabyte of RAM" :)
10:08dreishBut, the Amiga had more colors and was therefore better!
10:08ambientatari had a midi-port built-in
10:08ambient:)
10:09ambientthe times when normal computer magazines had articles like "how to program your C64 to read data from weather satellite"
11:53lambdatronichowdy 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:54lambdatronicI'm currently using Clojure 1.0.1-alpha-SNAPSHOT, and (= [] ()) and therefore (isa? [] ()) returns true.
11:55lambdatronic(isa? () []) also returns true.
11:56lambdatronichowever, none of the other empty collection values are equivalent [i.e. (isa? () {}) (isa? () #{}) (isa? [] {}) (isa? [] #{}) (isa? {} #{}) (isa? {} []) (isa? {} ()) (isa? #{} ()) (isa? #{} []) (isa? #{} {})]
11:56lambdatronicSo what gives?
11:57rhickeylambdatronic: isa? is not about instances, it's about types, so don't confuse with instance? or =
11:57rhickeywhen used with aggregates (i.e. vectors), it is about aggregates of types
11:57lambdatronichowever, isa? performs = first before traversing type hierarchies.
11:58rhickey(isa? [String String] [Object Object])
11:58lambdatronicand its (= () []) that's throwing this all off.
11:58lambdatronicthe = fails on all the other sentinel values as well.
11:59rhickey(isa? {} []) is not meaningful
11:59rhickeythey are not types not aggregates of types
11:59rhickeythe only supported aggregate is a vector of types/tags
12:00lambdatronicWhen 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:01Chousukean empty list is structurally equivalent to an empty vector, I suppose.
12:01rhickeylambdatronic: 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:03rhickey(and (sequential? []) (sequential? ())) -> true
12:03lambdatronichmm...but {} and [] don't compare equal although the key/val mapping functions both work on them.
12:04rhickeyright, there will always be overlap in behaviors of collections, sequential/map/set is just one way to separate them
12:04rhickeya vector is not a full map, even though it is somewhat associative
12:05lambdatronicalright, 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:06rhickeythe whole phrase 'underlying collection type' implies a lumping already, i.e. sorted and hashed sets, many flavors of maps
12:08lambdatronicright, 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:08lambdatronicbut now I know, I guess, and knowing is the half the battle.
12:08lambdatronic;)
12:08rhickeyequality 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:09lambdatronicah, therein lieth the rationale.
12:09lambdatronicit's a javaism.
12:11lambdatronicI see now the other spooky things one can do with this => (= [1 2 3 4] (seq #{1 2 3 4}))
12:11lambdatronicor (= '([1 2] [3 4]) (seq {1 2 3 4}))
12:12rhickeylambdatronic: 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:13lambdatronicyeah, I'm seeing that rich. hence my last two examples.
12:13rhickeythe 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:13lambdatronicthat is the presumption, yes.
12:14lambdatronicit'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:14rhickeyit 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:15lambdatronicI 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:15lambdatronicsure enough, dynamicity is the name of the game, after all.
12:16rhickeyI thought there were some docs on how collection equality worked, but can't find them now...
12:16lambdatronicit'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:16lambdatronicnor can I...
12:16rhickeyinstance? is what you want there
12:17rhickeyor the abstraction-blah? predicates
12:17lambdatronicyou mean like vector?, map?, seq?, list?, set?
12:18rhickeyyeah:
12:18rhickeyuser=> (seq? ())
12:18rhickeytrue
12:18rhickeyuser=> (seq? [])
12:18rhickeyfalse
12:18lambdatronichmm...sneaky
12:19lambdatronicso let me ask again quickly about the aggregates of types you were discussing earlier.
12:19lambdatronichow would I use that with isa?
12:20lambdatronicis it something like the opportunity to match multiple values?
12:20rhickeyexactly
12:21lambdatronicsorry, I didn't phrase that correctly...too ambiguous
12:21lambdatronicas in, is this a disjunctive or a conjunctive match?
12:22rhickeyconjunctive
12:23rhickeysince 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:24lambdatronicso 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:24lambdatronicok
12:25rhickeyvectors only
12:25lambdatronicso why are vectors the only allowed matchable collections?
12:25rhickeyfast count test
12:25lambdatronichmm
12:27rhickeybasically, they do the job and adding generatily wil lslow things down, no need here
12:28lambdatronicno worries, I've got a heuristic lexer/parser in my brain. ;)
12:29lambdatronicbut I see that multimethods will match on maps, sets, etc.
12:29lambdatronicas in, I just tried it, and it worked.
12:30lambdatronicso remind me again where the vector-only restriction comes into play? I get the sense I'm missing something important here.
12:30lambdatronicor just being dense.
12:31chousersince 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:32lambdatronicchouser: please see 3 posts back.
12:32chouserbut the position matters.
12:32lambdatronic(= {:a :b :c :d} {:c :d :a :b})
12:32lambdatronic
12:33lambdatronicand of course, that works just fine, as expected.
12:33lambdatronicagain, see the post I just made.
12:33chouserright, but often you want to check inheritence, not equality
12:34lambdatronicso when we're talking about the vector-only matching, we're strictly speaking about the inheritance checking post-equality testing?
12:35chouserwell -- I'm saying non-sequential things don't even make sense because of that. The restriction to vectors only may be more involved.
12:36rhickeylambdatronic: 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:36chouser(derive ::A ::D) (derive ::B ::C)
12:36chouser(isa? [::A ::B] [::D ::C]) ;=> true as you'd expect
12:37chouser(isa? #{::A ::B} #{::D ::C}) ;=> false, because it doesn't really make sense
12:38lambdatronicokay, I see your point now.
12:38lambdatronicit's just helpful with the clojure derive functionality.
12:39lambdatronicor the java class hierarchy too, of course
12:40rhickeyisa? 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:41chouseraddMethod could throw something if given an non-vector collection
12:41rhickeyisa? isn't bound to multimethods
12:42chouserright, but defmethod isn't speed critical like isa?
12:42lambdatronicyep, 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:43lambdatronicbut you cleared up your rationale for why (= [] ()) is true. so all is well in the world.
12:43rhickeychouser: but non vectors aren't wrong, if you want the equality test
12:43lambdatronicthanks again, guys. keep on hackin' in the free world. I'm out.
12:45rhickeyi.e. you could dispatch on sets, vectors just get 'isa-enhanced' equality
12:46chouserah, I see. I didn't realize isa? was explicitly checking for vectors before doing isa? on the items.
12:47rhickeythat needs better docs I guess
12:48rhickeyso 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:49rhickeythe 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:50rhickeyand 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:52chousergotta go buy carving pumpkins. bbl.
13:22ambienthow can I stop a macro from adding the namespace to the variable? http://paste.pocoo.org/show/146907/
13:23ambienti need evt and val just as they are, without any namespaces in front of them
13:23spuzDoes the clojure compiler generate intermediate .java files before the .class files are generated?
13:24robsynnottDoubt it; doesn't it generally compile to JVM bytecode, not java?
13:25spuzI expect so
13:26spuzbut perhaps there is some way to view the output of the compiler as generated java code...?
13:26ankou_hi, what exaclty is the graphical inspector?
13:26ankou_is there an article or something like that? can't find anything about this topic
13:26spuzI've tried decompiling the generated .class files but it really doesn't make sense as the code generated wouldn't appear to compile
13:27ambientclojure.contrib.swing-utils is a bit useless for me without a tutorial :(
13:32notallamaambient: ` adds namespace, ' doesn't. so you can unquote something and requote it like `(blah blah ~'x blah blah)
13:33ambientaha :)
13:34chouserspuz: Clojure compiles directly to bytecode that can in many cases not be represented correctly as .java
13:34spuzchouser: heh, thought as much :p
13:35somniumanyone tried using jad or similar on clojure's .class files?
13:37chouserankou_: (require 'clojure.inspector) (clojure.inspector/inspect-tree {:a 1 :b {:c 2 :d 3}})
13:43spuzsomnium: I've tried JD-GUI: http://java.decompiler.free.fr/?q=jdgui
13:43spuzsometimes it gives useful results
13:44spuzin my case though it seems the body of the function I'm looking at does absolutely nothing!
13:51AWizzArd~seen kotarak
13:51AWizzArdhiredman: bot gone?
13:53chouserrhickey: 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:59chouserright? so interop using reflection but sharing a classloader for a whole file might be closer to the right answer?
14:22spuzI'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:25rysthe closure closes over state
14:25rysThe anonymous function is just that
14:26rysIt's a function with no ident
14:26chouserspuz: without closures, 'x' would not be defined in (fn [y] (+ x y))
14:27spuzchouser: so you would get an error saying "x not defined in this context"?
14:27toupsIs 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:28Chousukeuse pmap with dorun
14:28chouserspuz: right
14:29toups(dorun (pmap (fn ...) sq))?
14:30toupsChousuke: like th at?
14:30Chousukeyeah
14:30toupsThanks
14:30Chousukespuz: anonymous functions and closures are orthogonal concepts. a named function can form a closure too.
14:31AWizzArdspuz: 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:31Chousukejust do (let [foo bar] (defn ...))
14:31spuzI've only ever seen closures using anonymous functions but that makes sense
14:32AWizzArdspuz: you can use Closures in non-anon functions as replacement for (Java) classes.
14:32Chousukethey're much more common as anonymous functions
14:32AWizzArdImagine you have a Point object, with the members x and y. You want to create a new point, or update one.
14:33AWizzArdYou could have a (let [x 0, y 0] (defn make-point ..) (defn distance ...)) and so on.
14:33AWizzArdThen 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:37toupswheee - clojure is pretty fun.
15:03Qvintvsdoes 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:04The-KennyQvintvs: Where in this code?
15:04Qvintvsline 33
15:08The-KennyQvintvs: The problem is in add-to-map called by get-words.
15:08The-KennyQvintvs: Do you really want to emit "words" two times to add-to-map?
15:11QvintvsThe-Kenny, ah, thx
15:13The-KennyQvintvs: I think zou also switched the last two values... v should be a number and not an object.
15:13The-Kennys/zou/you/
15:13QvintvsThe-Kenny, ya, i noticed that too
15:57hiredmanclojurebot: ping?
15:57clojurebotPONG!
15:57somnium,(#(%) #(+ 2 3))
15:57clojurebot5
15:58somniumhiredman: you turned off the I-Ching?
15:58hiredman(+ 1 4)
15:58clojurebot*suffusion of yellow*
15:59somniumoh good
16:05somnium,(doc rfirst)
16:05clojurebotExcuse me?
16:06somniumsome functions on the cheatsheet http://clojure.org/cheatsheet don't seem to be there
16:08hiredmanthe cheatsheat is kind of out of date
16:08hiredman,(doc nfirst)
16:08clojurebot"([x]); Same as (next (first x))"
16:09somniumis that what rfirst did, or was it (rest (first x))?
16:10licoresseIMO, look at http://www.daimi.au.dk/~eernst/dPersp08/cheatsheet.pdf for what I think clojure.org needs
16:11licoressethere was a similar "terse guide to Smalltalk", but I cannot find it anylonger
16:11somniumyeah, that would be nice, python has some good ones too
16:12somniummakes it easy for anyone to get started
16:13licoresseah, found it: http://74.125.77.132/search?q=cache:oaN12i4Gg0EJ:wiki.squeak.org/squeak/5699+terse+guide+to+squeak&amp;hl=en&amp;client=safari&amp;strip=1
16:13licoressethat one helped me a lot when I was beginning squeaking
16:14hircusman, Clojure maps are *fast* -- http://hircus.wordpress.com/2009/10/25/mini-kanren-benchmarking-different-substitution-data-structures/
16:15hircusrhickey: any chance we could get IMapEntry's getter renamed to value() ?
16:16somniumlicoresse: how did you learn to like the squeak gui?
16:17licoresseI didn't
16:17licoressebut when you have turtles all the way down
16:17licoresseyou learn to like anything
16:17licoresse!!
16:17licoresseso I was in love for a couple of years
16:17somniumlicoresse: too bad there's no emacs mode with buffers instead of windows
16:18danleipharo looks a lot nicer than the vanilla squeak images imho
16:18licoressesomnium: you mean workspaces?
16:18licoressethe problem with squeak as many other similar things is that they have their own ecosystem
16:19licoresseand integrate poorly to the rest of the world
16:20danleiI'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:21danleiit still is a nice environment though
16:21licoressewell, I am happy to admit that Clojure is my new love now
16:21somniumI 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:21licoresseI only wish someone would do a proper debugger thing in emacs
16:21danleisomnium: I know what you mean :)
16:22licoressesomnium: it's not so much the language, which is fine, but more the environment
16:23licoressethe concepts of do-its, print-its etc
16:23licoresseand that brilliant debugger
16:23danleifor cl, the inspector and debugger are actually quite nice, don't get in your way
16:23danlei(slime)
16:24licoressedanlei: but none of that is avail to clojure, is it?
16:24danleino, not that i'm aware of
16:28somnium'show and 'source in repl-utils do most of what I want for insepcting, but I don't what the CL inspector does
16:28notallamapointfree stuff is coming along nicely. i should probably do my homework, though :V http://github.com/hclarke/pointfree-clojure
16:29danleisomnium: there are restarts, eval-in-frame, goto-source ...
16:29hiredmanoooo
16:29danleisomnium: you can eval code in a stack frame an restart it, for example
16:29danlei*and
16:30somniumnotallama: that looks nice, I was lamenting the lack of something like your &&& and *** just yesterday
16:30djorkoh man I would kill for a Squeak-like debugger in Clojure
16:31djorkactually I just want Clojure errors instead of Java errors
16:31djorkstack traces tha tis
16:31licoressedjork: that would help
16:32licoresseor that the *slime-messages* buffer scrolls correctly
16:32djorkheh yes that too
16:32hiredmanhave you tried out clojure.stacktrace?
16:32somniummy favorite is 'no message', java null pointer, no source
16:32licoresseguess that is an easy thing to "fix"
16:33licoressehiredman: no, I have not
16:33licoresseanyone written about it, a blog or something?
16:34hiredmannope
16:34hiredmanI only found it because my reader was barfing on it while I was using it to build clojure
16:34djorkhah
16:35licoresseooo
16:35licoressehttp://img.skitch.com/20090721-efy2e4wgsrhxs2cxsbnu4c4ftx.png
16:36somniumisn't that what slime does?
16:36licoressesans colors
16:36somniumtrue
16:37robsynnottooh, pretty
16:38djorkwow, nice
16:38djorkslime doesn't look like that for me
16:39djork 1: user$eval__6140.invoke(NO_SOURCE_FILE:1)
16:39djorkoh duh
16:39djorknevermind
16:41danleihttp://danlei.nfshost.com/sldb.png
16:41danleithat would be nice to have in clojure too
16:42somniumwow
16:42somniumI hope something like that is in the works somehow or other
16:42danleiand that's just the top of the iceberg
16:43danleiwell,
16:43danleithe problem is, that for example "restart" are a feature of the cl condition system
16:43danleiit's not a slime thing per se ...
16:43Chousukethe JVM just has exceptions :/
16:43licoresse'clojure.stacktrace is actually quite nice
16:44licoressejust need to connect it properly to the 'slime-compilation-finished-hook
16:44danleiin 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:45danleiif no handler handles a condition, it will be handled by a human, in the debugger
16:45ChousukeI wonder what it would require for Clojure to emulate the condition system.
16:45somniumlicoresse: could you paste the .emacs line you used?
16:45Chousukethere's error-kit but... hm.
16:46licoressesomnium: it's just a (add-hook 'clime-compilation-finished-hook 'whatever-you-like)
16:46licoresseslime (not clime)
16:46somniumlicoresse: so just 'clojure.stacktrace there?
16:46licoresseno no
16:46licoresseyou need to call swank
16:47licoresseor send something to the swank process or whatever
16:47licoresseI am not completely understanding this yet
16:47somniumlicoresse: ah, I thougt you had it hooked up already
16:47licoresse:-(
16:48Chousukeor you can bug technomancy to add it to swank-clojure next time he joins :P
16:48somniumlicoresse: I've been putting off reading swank-clojure.el
16:48licoresseanyway, I think that the above-mentioned hook is only called when the compilation is successful, I have to test it more
16:49Chousukeit shouldn't be too difficult to conditionally enhance the repl if contrib is available.
16:49licoresseI lost the link, there was someone mentioning clojure in emacs
16:50licoresselike, extending elisp with clojure stuff
16:50licoressesomnium: swank-clojure.el is a mess
16:51licoresseI guess that is what you get when everything is global
16:51somniumlicoresse: I know, I looked at it once :)
16:51Licenserow a lot is going on here
16:52somniumI think I like it best as a black box
16:52licoresseheh
16:54licoressewait 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:55licoresseit's just 250 lines long
16:55somniumI'm sure it makes perfect sense once it makes sense to you
16:57hiredmanhttp://www.thelastcitadel.com/images/syntax.png this is a mess
16:57somniumheh
16:57licoressehehe
16:58licoresseis that object oriented?? :D
16:58hiredmanI spent a large chunk of yesterday tracing that out
16:58somniumI like in once of rich's presentations he had one of those with "There Will Be A Quiz!" in big letters
16:59hiredmanthat is the syntaxQuote method from SyntaxQuoteReader in clojure.lang.LispReader
16:59hiredmanthat is all in one method
16:59somniumgood god
16:59licoresseouch
16:59hiredmanonce I made the graph it made sense, but before that :(
17:01somniumhiredman: it reminds me of the inside of a neglected server
17:02licoresseactually most of it makes sense, it's just that when you graph it...
17:02somniumhttp://www.michaelaulia.com/blogs/wp-content/uploads/2009/10/messy-cable-solution.png
17:03licoressehmm
17:08Chousukehiredman: I think the worst part of implementing syntax-quote is the symbol resolution :P
17:10licoressehehe, reading about CIP (Clojure Idiomatic Police)...
17:10hiredmanwe have those?
17:10Chousukehttp://github.com/Chousuke/clojure/blob/sq-macro/src/clj/clojure/core.clj#L562 I'm still not sure this is right.
17:11Chousukealso I wonder why there is no syntax-highlighting :/
17:12hiredmanthe graph really helped me understand the flow
17:14hiredmanI have five places where my reader still relies on LispReader: ReaderException, FnReader, ArgReader, EvalReader, and readDelimitedList
17:14Chousuke!
17:14ChousukeI might just have figured out the bug I have compiling Clojure with my reader.
17:15Chousukeepiphany out of nowhere
17:15hiredmanhuzzah!
17:15licoressehow wonderful!
17:15Chousukenow I hope I'm right.
17:17notallamais 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:17Chousukecontrib has static-import I think. maybe that would help?
17:21somniumdoes (into {} ...) always create an ArrayMap regardless of number of args?
17:21Chousuke,(class (into {} [1 2]))
17:21clojurebotjava.lang.IllegalArgumentException: Don't know how to create ISeq from: Integer
17:22Chousuke... ?
17:22Chousukeah
17:22Chousuke,(class (into {} [[1 2]]))
17:22clojurebotclojure.lang.PersistentArrayMap
17:23Chousukehmm.
17:23Chousuke,(class (into {} (take 15 (repeatedly [1 2])))
17:23clojurebotEOF while reading
17:23Chousuke,(class (into {} (take 15 (repeatedly [1 2]))))
17:23clojurebotjava.lang.RuntimeException: java.lang.RuntimeException: java.lang.IllegalArgumentException: Wrong number of args passed to: PersistentVector
17:23notallamaChousuke: yes, that is exactly what i needed. thanks! (it's called import-static)
17:23Chousuke,(class (into {} (take 15 (repeat [1 2]))))
17:23clojurebotclojure.lang.PersistentArrayMap
17:23somnium,(class (into {} (interleave (range 100) (range 100))))
17:23clojurebotjava.lang.IllegalArgumentException: Don't know how to create ISeq from: Integer
17:23Chousuke,(class (into {} (take 50 (repeat [1 2]))))
17:23clojurebotclojure.lang.PersistentArrayMap
17:24Chousukeapparently :/
17:24somniumhmm
17:24Chousuke,(class (into {} (take 5000 (repeat [1 2]))))
17:24clojurebotclojure.lang.PersistentArrayMap
17:24Chousuke...
17:24somniumwell, on the bright side, that means I have some very easy optimizations to implement :)
17:24Chousukesorry, I'm stupid :D
17:24Chousukeall those maps had only one element.
17:24hiredmanhaha
17:24Chousukeshould go to sleep.
17:25somnium,(class (into {} (partition 2 (interleave (range 100) (range 100)))))
17:25clojurebotjava.lang.ClassCastException: java.lang.Integer cannot be cast to java.util.Map$Entry
17:25hiredman,(class (into {} (map vector (range 100) (range 100))))
17:25clojurebotclojure.lang.PersistentHashMap
17:25somniumah
17:25somniumwell, that solves that
17:32somnium(conj {} [1 2])
17:32somnium,(conj {} [1 2])
17:32clojurebot{1 2}
17:32divhiredman: 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:32somnium,(conj {} '(1 2))
17:32clojurebotjava.lang.ClassCastException: java.lang.Integer cannot be cast to java.util.Map$Entry
17:33hiredmandiv: that is graphviz
17:33divwhat's with the scary lines :)
17:34divthe boxes are familiar yes, but it just seems like you drew the connections with paint :p
17:34hiredmanthe dark arrows are control flow and the thin lines are, uh?, state flow?
17:34hiredmannah, it's all dot
17:35divi see
17:36somniumhmm, I guess (into {} '(:foo :bar)) isn't supported for performance reasons?
17:37hiredmaneh?
17:37hiredmanwhere are the keys and values?
17:38somniumit seems to be because lists don't implement IEditableCollection
17:38somniumbut [:foo :bar] does
17:38somniumso that was the basis for my guess
17:39hiredmanno
17:40somniumer, scratch that, re-reading into
17:40hiredman(into {} [:foo :bar]) and (into {} '(:foo :bar)) both won't work
17:40somniumI know
17:40hiredman(into {} '([:foo :bar])) does work
17:41somniumhmm
17:41hiredman(conj {} :foo :bar) doesn't work
17:41hiredman(conj {} [:foo :bar]) does
17:46AWizzArdthough i find (assoc {} :foo :bar) documents the code better
17:47hiredmansure
17:47hiredmanI'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:48AWizzArdyes
17:51Licensersomnium: how is the mongodb driver going?
17:51somniumLicenser: a pre-alpha version is on github, its working but test coverage is poor
17:52Licenserwooh
17:52somniumLicenser: would be happy if you give it a try and let me know how it goes
17:52somniumbeen writing tests this afternoon
17:52Licensersomnium: I'm planing on it ;)
17:53Licensersomnium: how is it named?
17:54hiredmanclojurebot: how is it named?
17:54clojurebotwith style and grace
17:55Licenserah found it
17:56somniumI considered mongojure and clomongo but they didn't appeal
17:56Licenserhah I tried mongojure :P
17:57somniummaybe 'clongo wouldn't be so bad
17:58piccolinosomnium, so cool. I was just a week ago wishing there was a MongoDB driver for clojure taht worked like this.
17:59somniumpiccolino: 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:00somniumhiredman: 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:02Licensersomnium: I'm excited over your driver :P
18:02hiredmanit's a call to the conj static method on RT
18:03hiredmananway, conj on maps takes a key-value pair
18:03hiredman'([:key :value]) is a sequence containg a key-value pair
18:04hiredman'(:foo :bar) is not
18:04somniumhiredman: ok, been putting off reading the .java portion of clojure, thanks
18:05hiredmansomnium: you don't need to
18:06hiredmanthe point is '(:foo :bar :baz :bleep) is a flat sequence, '([:foo :bar] [:baz :bleep]) is a sequence of two element vectors
18:07somniumhiredman: right, but (list (list 1 2) (list 2 3)) also doesn't work, which is a sequence of two element sequences, or no?
18:07hiredmanthe first will not work because a. into uses conj (or did last time I checked) and b. it contains no key/value groupings
18:07somniumso I assume it has to do with how conj works
18:07hiredmanthat is because conj for maps takes a map entry, and two element vectors are map entries
18:08hiredman,(class (first {:a :b}))
18:08clojurebotclojure.lang.MapEntry
18:08hiredman,(first {:a :b})
18:08clojurebot[:a :b]
18:10somniumhiredman: ah, now it clicked, I wasn't thinking about the definition of map entries
18:24hiredmaninteresting 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:24LauJensen~seen jdz
18:24clojurebotno, I have not seen jdz
18:30Licensersomnium: from the docs your API looks very neat
18:32somniumLicenser: 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:33Licenserhmmm
18:34somniumLicenser: hopefully I'll get the core test suite finished this evening
18:34LicenserI have a request so :P fetch-one-with-defaults that would be very sweet
18:34Licensers
18:34Licenseri
18:34Licensersince in the KV store you never can know what you get
18:34somniumLicenser: how would that work?
18:34Licenserwell like:
18:35Licenser(fetch-one-with-defaults :robots :where {:name 'rodney'} :defaults {:type 'killer robot with laser eyes'})
18:36Licenserso 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:36hiredmanwatch the single quotes
18:36somniumah
18:36Licensersince I don't think mongodb allows field defaults as it has no scemes
18:36Licenserhiredman: thanks
18:37piccolinoDoes it work with hierarchical objects?
18:37Licenserpiccolino: it does not work at all :P it's a dream of mien
18:37piccolinoSorry, I was asking somnium about the main functionality. :)
18:38piccolinoI see that map-to-object just calls the mongo-java function, not sure how that one works yet.
18:38somniumpiccolino: 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:39somniumor BSON I guess, but whatever, the structure is just like JSON
18:39piccolinoSo if I put a clojure map in a clojure map, the Java API will correctly structure that?
18:39AWizzArdyes
18:39piccolinoCool.
18:40AWizzArdyou can also use the json parser in Clojure Contrib.
18:42somniumpiccolino: they mongodb-java-driver also has a JSON/parse method that creates mongo objects, will probably wrap that in the next release
18:43somniumpiccolino: 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:43piccolinoTotally, that's how it should be.
18:47piccolinoI just guess the Java MongoDB driver had more reflection than I realized.
18:48ankou_hi, is there a simple search function like (first (filter x y)) but more efficient?
18:49somniumpiccolino: 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:49piccolinoWhat would be the advantage of that?
18:49somniumpiccolino: speed most likely
18:50somniumankou_: try (some x y)
18:50hiredmansome returns the result of the predicate
18:51ankou_which is true and not the element itself
18:52hiredmanankou_: what is the problem with (first (filter ...))
18:53ankou_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:54somnium,(some #(if (string? %) % nil) '(:foo :bar "yes" :wow))
18:54clojurebot"yes"
18:54somniumthough I don't suppose that's better than (first (filter ...))
18:56hiredmanankou_: unless the input is sorted you are going to have to do a linear search, which is exactly what (comp first filter) does
18:58somnium,(time (first (filter #(= 2000 %) (iterate inc 1))))
18:58clojurebot2000
18:58clojurebot"Elapsed time: 13.013 msecs"
18:59somnium,(time (some #(if-let [x (= 2000 %)] x) (iterate inc 1)))
18:59clojurebottrue
18:59clojurebot"Elapsed time: 9.003 msecs"
18:59somniumbah
19:00somnium ,(time (some #(if (= 2000 %) %) (iterate inc 1)))
19:00hiredman,(time (some #{2000} (iterate inc 1)))
19:00clojurebot2000
19:00clojurebot"Elapsed time: 11.467 msecs"
19:00somniumnice, I don't use sets nearly often enough
19:02somnium,(time (first (filter #(= 100000 %) (iterate inc 1))))
19:02clojurebot100000
19:02clojurebot"Elapsed time: 383.559 msecs"
19:02somnium,(time (some #(if (= 100000 %) %) (iterate inc 1)))
19:02clojurebot100000
19:03clojurebot"Elapsed time: 168.427 msecs"
19:04somnium(time ((comp first filter) #(= 100000 %) (iterate inc 1)))
19:04somnium,(time ((comp first filter) #(if (= 100000 %) %) (iterate inc 1)))
19:04clojurebot100000
19:04clojurebot"Elapsed time: 218.176 msecs"
19:05somniumhiredman: internally, how different are (first (filter ...)) (comp first filter) ... and (some ...) ?
19:05somniumor at all?
19:06hiredman(comp first filter) creates a new function
19:07hiredman(first (filter ...)) doesn't
19:07hiredmanwhich means there is an extra function invocation too
19:08somniumhmm, some and filter are very different
19:09hiredman~def some
19:09somniumwhy is filter so complicated?
19:09ataggartsome is the complement of any
19:09ataggarterm
19:09hiredmansome is not lazy
19:09hiredmanfilter is
19:10ataggartevery? not any, sry
19:10somniumof course, and filter returns a whole collection, duh
19:11somnium'some' maybe isn't the best name for what it actually does, 'first-truthy' ?
19:11hiredmantrue for some elements
19:11hiredmansome
19:11ataggartI like "any?"
19:12somniumhiredman: is there any way you could wire up clojurebot to 'source in repl-utils?
19:12somnium-> (defn some [pred coll] (when (seq coll) (or (pred (first coll)) (recur pred (next coll)))))
19:13hiredman,(use 'clojure.contrib.repl-utils)
19:13clojurebotjava.lang.ExceptionInInitializerError
19:13hiredmanclojurebot: same to you!
19:13clojurebotIt's greek to me.
19:14danlei,(require '[clojure.contrib.repl-utils :as ru])
19:14clojurebotjava.lang.NoClassDefFoundError: Could not initialize class clojure.contrib.repl_utils__init
19:15danleididn't that use to work?
19:21hiredman,(use 'clojure.contrib.repl-utils)
19:21clojurebotnil
19:21hiredman,(source 'some)
19:21clojurebotjava.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol
19:21hiredman,(source some)
19:21clojurebotSource not found
19:21hiredman:P
19:21somniumhiredman: is there anyway you could put the .clj files on his classpath without compromising his sandbox?
19:49merijnDo 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:51notallamathey can be. i think it's closer to guards.
19:52somnium-> ((f x y z) x y z)
19:53somniumhow does haskell's pattern matching work?
19:56merijnsomnium: 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:56merijnerr.. sum (tail list) in the latter example, of course
19:57notallamait's basically a destructuring bind, and you can put literals in it to match against.
19:58somniumx:xs = [x & xs] ?
19:59hiredmansort of
20:00notallamasomnium: [[x & xs]], i think
20:00merijnsomnium: ":" is list concatenation, so (x:xs) is a list with the first element bound as x and the tail bound as xs
20:00hiredmansome wrote a pattern matching macro
20:00hiredmansomeone
20:00hiredman~matches
20:00clojurebotexcusez-moi
20:01hiredman~google clojure pattern matching
20:01clojurebotFirst, out of 1630 results is:
20:01clojurebotbrool » Pattern Matching In Clojure
20:01clojurebothttp://www.brool.com/index.php/pattern-matching-in-clojure
20:01somniumhiredman: ooh, I was thinking about writing one yesterday
20:02merijnhiredman: 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:03somnium(doc match)
20:03clojurebot"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:03notallamamerijn: multi-methods are more general. they dispatch on any function of the arguments you can think of.
20:04somniumare there any code examples for contrib.macros/macro-utils ? in the wild or elsewhere ?
20:04hiredmannice
20:04hiredmanmatching on constructor forms is great
20:04notallamaso, it could choose a method by type, or by value, or by length of a string, or whatever.
20:05somniumI really wish there was a cheatsheet for contrib, I keep finding stuff I didn't know was thre
20:05merijnnotallama: ok
20:19Licenserwow the mongodb community is quite fun
20:22somniumLicenser: ?
20:23Licensersomnium: yap, I just asked a question and ran into a bug, they are very helpfull in the channel :P
21:20tomojtechnomancy: do you happen to know who maintains elpa gist.el?
23:12technomancytomoj: no, sorry
23:21lisppaste8djork pasted "why does this throw a NPE?" at http://paste.lisp.org/display/89274
23:22djorkIf anybody can explain this mysterious error to me, I'd appreciate it.
23:22hiredman,(first '())
23:22clojurebotnil
23:22djorkah
23:22djork,(dec nil)
23:22hiredman,(dec (first '()))
23:22clojurebotjava.lang.NullPointerException
23:22clojurebotjava.lang.NullPointerException
23:22djork:)
23:23djorkthanks
23:23djorkby the way, iterate is a brilliant thing
23:24djorkI love the fact that I can just do (nth (iterate next-day [5]) 1234)
23:24djorkbrilliant stuff
23:24djorkof course my algo. here is not going to work (stack overflow)
23:26djorkwhat's the best way to put conj and recur together so that I have a tail-recursion going on?
23:58chouserdjork: walking a lazy seq shouldn't overflow the stack