2009-03-29
| 00:33 | dreish | 10^100 == 2^100 * 5^100. 2^100 is obviously divisible by 2^32. So (int (.pow 10M 100)) is 0. |
| 01:36 | slashus2 | Does the writer function in duck_streams allow for appending? |
| 01:38 | slashus2 | When i wrote my with-out-file macro I used FileWriter so that I could use the append functionality. |
| 01:38 | slashus2 | The new with-out-writer doesn't seem to support appending. |
| 03:19 | Raynes | I think Clojure has ruined me. Everything I think about learning another language, something about Clojure makes me dread it. :| |
| 03:21 | cmvkk | that's funny because, thanks to clojure being written in it, i've been learning java for the first time. |
| 03:21 | cmvkk | clojure has brought me closer to 'bad' languages. |
| 03:21 | Raynes | Why would you learn a language just because another language is written in it. :| |
| 03:22 | cmvkk | for clojure's sake, it's a boon to know java. for one thing, I can read the clojure source better which will make me better with clojure. |
| 03:23 | cmvkk | but also, it means i can implement part of a clojure library in java if i want, extend clojure from java, etc. |
| 03:23 | clojurebot | it is too |
| 03:24 | slashus2 | clojurebot: indeed |
| 03:24 | clojurebot | It's greek to me. |
| 03:24 | cmvkk | i'm currently thinking about writing a small 2D game engine in java, but in such a way that it's easy to extend from clojure. |
| 03:24 | Raynes | I want to learn Scala or Java. |
| 03:25 | Raynes | But I'm worried if I learn Java, I'll become corrupted. |
| 03:25 | cmvkk | worried that you'll see everything in an object-oriented light, and start to add needless OO code to your clojure programs? |
| 03:26 | slashus2 | Raynes: It just feels more rigid. Using a good IDE like netbeans helps. |
| 03:26 | cmvkk | i personally think that knowing more languages can only make you a better programmer. |
| 03:27 | Raynes | I'm worried that I'll forget how great functional programming is. I'm worried that learning Clojure before learning an OO language will cause me to program horribly in Java. |
| 03:27 | slashus2 | Righting things in the oo paradigm is sort of like a game. How can I model this problem into a complex, object oriented scheme? |
| 03:27 | slashus2 | Writing rather |
| 03:27 | slashus2 | need to go to sleep. |
| 03:27 | cmvkk | it's uh, really hard to not program OO in java. rather than code horribly in java, you'll just end up being frustrated. |
| 03:28 | cmvkk | you'll want to program in a functional style, but then it turns out that you can't. |
| 06:11 | maacl | I get "java.lang.RuntimeException: You need to use "Import Library" to add processing.core.PGraphicsJava2D to your sketch." when I try to run the clj-processing example, even if I and PGraphicsJava2D to the imports ((:import (processing.core PApplet PGraphicsJava2D)) - any ideas anyone ? |
| 06:18 | Lau_of_DK | Top of the morning gents |
| 06:18 | hiredman | the very top indeed |
| 06:18 | maacl | Lau_of_DK: hey |
| 06:22 | maacl | Lau_of_DK: have you used clj-processing ? |
| 06:22 | Lau_of_DK | No sir |
| 06:37 | AWizzArd | What is clj-processing good for? |
| 06:50 | Lau_of_DK | Anybody here found some interesting ways to couple servlets and ajax ? |
| 07:00 | Lau_of_DK | Im thinking ala Symbolic Web |
| 07:08 | maacl | Lau_of_DK: can't say that I have |
| 07:54 | antifuchs | oh wow, clj-processing. neat! |
| 07:59 | maacl | antifuchs: yeah, except I can't get the examples to work |
| 08:02 | antifuchs | how so? not behaving properly or are you getting errors? |
| 08:02 | maacl | antifuchs: I get "java.lang.RuntimeException: You need to use "Import Library" to add processing.core.PGraphicsJava2D to your sketch." when I try to run the clj-processing example, even if I and PGraphicsJava2D to the imports ((:import (processing.core PApplet PGraphicsJava2D)) |
| 08:04 | antifuchs | hmm, it's a couple months old, maybe either processing changed? |
| 08:04 | antifuchs | s/either// |
| 08:08 | maacl | antifuchs: can you get it to work ? |
| 08:08 | antifuchs | haven't tried yet... I promised myself I would not hack on stuff today (: |
| 08:08 | antifuchs | tomorrow, though |
| 08:09 | maacl | antifuchs: if you figure it out I would love to hear from you |
| 08:09 | antifuchs | sure thing |
| 08:10 | AWizzArd | maacl: when you are in a repl and do (import '(processing.core PGraphicsJava2D)) and then type PGraphisJava2D, what does happen? |
| 08:11 | AWizzArd | If that beast was imported correctly then PGraphisJava2D should eval to the class processing.core.PGraphisJava2D |
| 08:12 | maacl | AWizzArd: hang on |
| 08:15 | maacl | AWizzArd: yeah it does eval to PGraphicsJava2D |
| 08:19 | AWizzArd | ok, that sounds good, it means that the import did work |
| 08:20 | maacl | AWizzArd: yeah but I can't figure out what to do to fix it |
| 08:26 | AWizzArd | is Processing some kind of graphics program? |
| 08:27 | maacl | Aw |
| 08:27 | maacl | AWizzArd: yeah, it is a data visualization tool |
| 08:28 | AWizzArd | ok |
| 08:31 | noidi | is it possible to use System/loadLibrary in clojure to load dynamic libraries? |
| 08:32 | noidi | i tried to port a simple "JNI hello world" from java to clojure but the loadLibrary doesn't seem to be working |
| 08:33 | noidi | i guess it has something to do with clojure using multiple classloaders, whatever they are :P |
| 09:33 | hjlee | ,(clojure.contrib.math/exact-integer-sqrt 1000000000000) |
| 09:33 | clojurebot | java.lang.ClassNotFoundException: clojure.contrib.math |
| 11:16 | mozinator | For those who might be interrested, I managed to make music with clojure + jmusic: http://mozinator.eu/?p=16 |
| 11:17 | cmvkk | mozinator: very cool. i'm working on a similar project: http://github.com/cmvkk/lumenc/tree/master |
| 11:17 | mozinator | cmvkk, cool ! |
| 11:17 | mozinator | cmvkk, going to check it ou |
| 11:17 | mozinator | t |
| 11:18 | duck1123 | too bad I'm not a musician |
| 11:19 | duck1123 | years ago I learn the piece of music I was supposed to be practicing by programming hypercard to play it when i clicked a button |
| 11:21 | AWizzArd | mozinator: does jmusic talk to the hardware midi, or does it support very high quality software instruments? |
| 11:23 | mozinator | AWizzArd, don't know really, I just bumped into it via http://www.fatvat.co.uk/2009/02/jmusic-and-clojure.html and thought it was cool to let it make music live, instead of writing it to a midi file first |
| 11:25 | AWizzArd | yes, sounds good |
| 11:27 | mozinator | the thing I would like to accomplish is to make music on the fly |
| 11:27 | mozinator | a little bit like this: http://www.infoq.com/presentations/archaeopteryx-bowkett |
| 11:27 | AWizzArd | sounds also interesting for me.. maybe I could combine this with my GP engine |
| 11:28 | mozinator | AWizzArd, GP engine ? |
| 11:28 | AWizzArd | Genetic Programming |
| 11:29 | mozinator | AWizzArd, sounds like a cool idea, go for it :) |
| 11:29 | mozinator | I got to go, visiters |
| 11:29 | AWizzArd | l8rs |
| 13:29 | MikeSeth | AM HOOKED! |
| 15:03 | johanm | I have a question regarding swank-clojure, if anyone is up for it: if I eval a (ns ...) expression with C-M-x, my *slime-repl clojure* does not switch to that namespace. I can switch to it at the repl (and the imports have been picked up, etc.), but consequent evals from my source file is evaluated for the default "user" namespace (meaning I can't use my imports). Am I doing it wrong? |
| 15:08 | dysinger | how do I get auto-indentation in the command line repl like I can for emacs? Is there any .inputrc trickery to be had? |
| 15:46 | AWizzArd | johanm: if you eval a (ns ..) in a code file, then in that file you will be in that namespace from that moment on. All functions that you write into that same file and that you eval there, will become available in the repl under that namespace. |
| 15:59 | johanm | AWizzArd: yeah, but when I eval the (ns ...) i emacs the slime repl does not change to the specified namespace (as indicated by the prompt), like it does when you're running clojure-mode without slime, for example (I'm using slime, swank-clojure and clojure-mode from cvs/git) |
| 16:04 | Lau_of_DK | This is border-line off topic, but since Im driving with compojure, I figured you'll cut me some slack: I have an menu which dynamically expands when you hover your mouse on it, problem is, it pushes the entire rest of the page down when expanding - how do I avoid this? |
| 16:09 | Lau_of_DK | got it, z-index + absolute positioning |
| 16:09 | Lau_of_DK | thanks for nothing guys - whats keeping everyone so busy? |
| 16:10 | chessguy | and i know nothing about clojure anyway. that's why i'm here :) |
| 16:11 | Lau_of_DK | Welcome to :) |
| 16:16 | chessguy | welcome to smile? is that what clojure is all about? |
| 16:18 | astor | I've been away from clojure for a few months, and after updating to the latest lazy-seq stuff, I'm faced with the following issue. (def *foo* (some-lazy-func)) gives java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to clojure.lang.IFn |
| 16:19 | Lau_of_DK | try wrapping your lazy-func in (seq) or (cons ...) |
| 16:19 | Lau_of_DK | chessguy, "Welcome to" was a sentense in itself, the smile was my warm welcome |
| 16:19 | astor | (def *foo* (seq (some-lazy-func)) gives the same problem |
| 16:19 | Lau_of_DK | Clojure is about functional concurrent lisping |
| 16:19 | Lau_of_DK | astor, go to the pastebin |
| 16:19 | chessguy | is there a bot in here that interprets snippets? |
| 16:20 | cmvkk | ,(+ 2 3) |
| 16:20 | clojurebot | 5 |
| 16:20 | chessguy | nice |
| 16:20 | Lau_of_DK | ,(doc cons) |
| 16:20 | clojurebot | "([x seq]); Returns a new seq where x is the first element and seq is the rest." |
| 16:21 | chessguy | ,(list 1 2 3) |
| 16:21 | clojurebot | (1 2 3) |
| 16:21 | chessguy | ,(car (list 1 2 3)) |
| 16:21 | clojurebot | java.lang.Exception: Unable to resolve symbol: car in this context |
| 16:21 | Lau_of_DK | car.... :) |
| 16:21 | chessguy | just checking :) |
| 16:21 | Lau_of_DK | You got in here from last century ? |
| 16:21 | chessguy | haha |
| 16:21 | cmvkk | you know, i thought i would miss car and cdr. |
| 16:21 | chessguy | been watching SICP :) |
| 16:22 | Lau_of_DK | I dont mis car and cdr, but I sometimes need cardrradrrdadrrr |
| 16:22 | chessguy | ,(first (1 2 3)) |
| 16:22 | clojurebot | java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn |
| 16:22 | Lau_of_DK | clojurebot: SICP ? |
| 16:22 | clojurebot | No entiendo |
| 16:22 | Lau_of_DK | clojurebot: SICP ? |
| 16:22 | clojurebot | Titim gan �ir� ort. |
| 16:22 | Lau_of_DK | Argh |
| 16:22 | qwert666 | is pattern matching available in clojure ? like in scala or haskell |
| 16:22 | Lau_of_DK | There was a page with the SICP code ported to Clojure |
| 16:22 | chessguy | ,(first '(1 2 3)) |
| 16:22 | clojurebot | 1 |
| 16:22 | chessguy | ah |
| 16:22 | cmvkk | qwert666, not quite |
| 16:22 | chessguy | so without the quote it was trying to apply 1 to the arguments 2 and 3? |
| 16:23 | cmvkk | mostly (i guess?) because there aren't types to match against |
| 16:23 | hiredman | clojurebot: sicp? |
| 16:23 | clojurebot | sicp is http://web.mit.edu/alexmv/6.001/sicp.pdf |
| 16:23 | hiredman | clojurebot: sicp? |
| 16:23 | clojurebot | sicp is http://www.codepoetics.com/wiki/index.php?title=Topics:SICP_in_other_languages:Clojure:Chapter_1 |
| 16:23 | qwert666 | cmvkk: so there is a chance that it will be implemented in the future ? |
| 16:24 | cmvkk | there is arity overloading, but i don't think rhickey likes the pattern matching aspect |
| 16:24 | cmvkk | so probably not? |
| 16:24 | cmvkk | there's destructuring too, which is kind of like that |
| 16:24 | Lau_of_DK | Guys - how do I center a div-tag which is positioned absolutely ? |
| 16:24 | chessguy | uh...wouldn't that be better to ask in #css or #html or something? |
| 16:24 | cmvkk | position it absolutely in the center? |
| 16:25 | Lau_of_DK | I need something like 50%x100px |
| 16:25 | cmvkk | yes that is too complicated |
| 16:25 | chessguy | ,(* (+ 2 (* 4 6)) (+ 3 5 7)) |
| 16:25 | clojurebot | 390 |
| 16:26 | hiredman | (* 4 6) |
| 16:26 | clojurebot | *suffusion of yellow* |
| 16:26 | chessguy | huh? |
| 16:26 | cmvkk | math operations returning colors |
| 16:27 | cmvkk | that's a little too cutting edge for me |
| 16:27 | hiredman | http://www.thateden.co.uk/dirk/ |
| 16:27 | astor | How do I rewrite this idiom which I use everywhere in my code using lazy-seq? http://clojure.pastebin.com/m5e0facc7 |
| 16:28 | slashus2 | lol |
| 16:28 | Lau_of_DK | astor, replace lazy-cons with cons I think |
| 16:28 | Lau_of_DK | Doesnt look like anything out of the ordinary |
| 16:29 | astor | more like http://clojure.pastebin.com/m7354eb77.. forgot the lazy-cons recursion in the first example. |
| 16:29 | astor | lazy-seq does not allow recur |
| 16:30 | cmvkk | your best bet is to put a lazy-seq, then use loop inside of the lazy seq |
| 16:30 | hiredman | uh |
| 16:30 | cmvkk | or something |
| 16:30 | astor | so I need defn, then fn, then lazy-seq, then loop, then recur+cons? |
| 16:30 | hiredman | I don't think that will work |
| 16:30 | astor | that's mighty complex. |
| 16:31 | hiredman | hmmm |
| 16:31 | hiredman | you don't need the fn |
| 16:31 | cmvkk | oh yeah. |
| 16:32 | cmvkk | (loop [[[f & r] s] s] ...) instead of the let and fn |
| 16:32 | hiredman | using lazy-seq typially looks like (defn f [x] (lazy-seq (cons (first x) (f (rest x))))) |
| 16:33 | hiredman | this lazy-seq looks like it just returns a laz-seq of even numbers is that correct? |
| 16:33 | astor | so I'd probably want something like (defn f [[f & r] x] (lazy-seq (cons f (loop ... (recur..) (f r))))) |
| 16:34 | cmvkk | not quite. |
| 16:34 | hiredman | (filter even? (iterate inc 0)) |
| 16:34 | cmvkk | (defn f [s] (lazy-seq (loop [[[f & r] s] s] (when f ...)))) |
| 16:34 | hiredman | will get you a lazy-seq of even numbers |
| 16:34 | cmvkk | or rather my-lazy-func instead of f there |
| 16:34 | cmvkk | then use cons instead of lazy-cons. but yeah, hiredman's right, just use filter. |
| 16:35 | hiredman | ,(take 10 (filter even? (iterate inc 0))) |
| 16:35 | clojurebot | (0 2 4 6 8 10 12 14 16 18) |
| 16:35 | hiredman | ~def filter |
| 16:36 | cmvkk | it's not quite that simple though, there's some weird destructuring going on in the input there |
| 16:36 | clojurebot | it is too |
| 16:37 | SethTisue | clojurebot is getting sassy |
| 16:37 | astor | my example is simplified, in real-life f takes several parameters which makes filter inadequate. |
| 16:38 | cmvkk | http://clojure.pastebin.com/d321a3117 astor |
| 16:38 | astor | sometimes I use reduce, but that's ugly because the initial condition is physically separate in the code. |
| 16:39 | astor | cmvkk: thanks |
| 16:39 | slashus2 | cmvkk: step isn't defined in that code. |
| 16:40 | cmvkk | it wasn't in the example code either...i don't think. |
| 16:40 | hiredman | given the similar structure of filter and your code I fard it hard to believe that you cannot just use filter |
| 16:40 | AWizzArd | OT: anybody here who speaks russian? I have a very easy question :) |
| 16:40 | clojurebot | filter is not map |
| 16:40 | hiredman | clojurebot: thanks! |
| 16:40 | clojurebot | Gabh mo leithsc�al? |
| 16:41 | hiredman | ~translate to ru one ping, one ping only |
| 16:41 | clojurebot | ???? ????, ???? ?????? ???? |
| 16:42 | chessguy | i'm thinking the symbolic differentiation pattern-matching thing from the video version of SICP would be a nice first project |
| 16:43 | hiredman | chessguy: using zippers |
| 16:43 | chessguy | oooh |
| 16:43 | chessguy | is there a zipper module already? |
| 16:43 | hiredman | yes |
| 16:43 | hiredman | clojure.zip |
| 16:43 | chessguy | though...i don't know that a zipper is really necessary for that one |
| 16:44 | chessguy | recursion should be fine |
| 16:44 | hiredman | correct |
| 16:44 | hiredman | but zippers are cool |
| 16:44 | cmvkk | i don't know what zippers are...am i missing out on the next big thing? |
| 16:44 | hiredman | http://clojure.org/other_libraries |
| 16:44 | chessguy | cmvkk: zippers aren't really new |
| 16:44 | cmvkk | heh |
| 16:44 | chessguy | http://en.wikipedia.org/wiki/Zipper_(data_structure) |
| 16:44 | hiredman | ,(require '[clojure.zip :as zip]) |
| 16:44 | clojurebot | nil |
| 16:45 | chessguy | reading the huet paper is a good start |
| 16:45 | cmvkk | oh i've heard of this |
| 16:45 | chessguy | though i seem to remember the code in the paper being in haskell, or close to it |
| 16:46 | astor | hiredman: typically you have something like (defn foo [x] (let [state {} step (fn [state [[f & r] x] (when f (if (complex-expression f) (recur (update-state state) r) (lazy-cons f (step r)))))] (step x)) |
| 16:46 | hiredman | ,(zip/seq-zip '(1 ? 3) zip/down zip/right (zip/replace 2) zip/root) |
| 16:46 | clojurebot | java.lang.IllegalArgumentException: Wrong number of args passed to: zip$replace |
| 16:46 | astor | there is probably a syntax error in there :-). the point is that there is additional state that is needed to figure out whether to recurse or not. |
| 16:46 | hiredman | ,(-> '(1 ? 3) zip/seq-zip zip/down zip/right (zip/replace 2) zip/root) |
| 16:46 | clojurebot | (1 2 3) |
| 16:46 | cmvkk | yes in fact, you can't use filter for that scenario. |
| 16:46 | clojurebot | filter is not map |
| 16:47 | chessguy | astor: are you saying a zipper is needed? |
| 16:47 | cmvkk | uh-oh, we're merging two conversations |
| 16:47 | chessguy | oh, whoops |
| 16:47 | chessguy | referential opqueness for the loss |
| 16:48 | hiredman | ,(pl inc $ inc $ inc $ 0) |
| 16:48 | clojurebot | 3 |
| 16:48 | cmvkk | i was going to say, this is where something like 'lazy-loop' would come in handy, but you couldn't do it with that kind of structure either. |
| 16:48 | cmvkk | the goal is to be able to recur a structure either with or without giving the next element. |
| 16:49 | hiredman | ,(pl (?map (replicate 3 range $ 3) call � (?map inc))) |
| 16:49 | clojurebot | ((1 2 3) (1 2 3) (1 2 3)) |
| 16:49 | chessguy | ,(replicate 3 range $ 3) |
| 16:49 | clojurebot | java.lang.Exception: Unable to resolve symbol: $ in this context |
| 16:50 | hiredman | pl is a macro that uses zippers |
| 16:50 | chessguy | ah |
| 16:50 | hiredman | ,(macroexpand '(pl range $ 3)) |
| 16:50 | clojurebot | (do (range 3)) |
| 16:51 | hiredman | and it only exists in clojurebot |
| 16:53 | Lau_of_DK | I got the absolute positioning down :) |
| 16:53 | Lau_of_DK | Man - The more I work with jQuery, the more I realize how powerful a clojure-wrap could be |
| 16:53 | chessguy | ,(do (range 3)) |
| 16:53 | clojurebot | (0 1 2) |
| 16:53 | slashus2 | hiredman: What does pl mean? |
| 16:53 | chessguy | clojure-wrap? |
| 16:53 | clojurebot | clojure is like life: you make trade-offs |
| 16:53 | Lau_of_DK | So I'll make the most full-featured wrapper imaginable, and keep it all to myself |
| 16:54 | Lau_of_DK | That'll teach you guys to ignore my questions :) |
| 16:54 | chessguy | what is do? |
| 16:54 | hiredman | slashus2: pointless |
| 16:54 | Lau_of_DK | do is a utility for gnome, which helps you reach your apps faster |
| 16:55 | chessguy | ,slap Lau_of_DK |
| 16:55 | clojurebot | java.lang.Exception: Unable to resolve symbol: slap in this context |
| 16:55 | chessguy | bah |
| 16:55 | Lau_of_DK | haha |
| 16:55 | Lau_of_DK | hiredman, thats bad PR right there |
| 16:55 | hiredman | ,(doc do) |
| 16:55 | clojurebot | java.lang.Exception: Unable to resolve var: do in this context |
| 16:55 | hiredman | bah |
| 16:55 | hiredman | do does things |
| 16:55 | Lau_of_DK | ,(loop [] (recur)) |
| 16:55 | hiredman | ,(do 1 (+ 1 2)) |
| 16:55 | Lau_of_DK | ,(loop [] (recur)) |
| 16:55 | Lau_of_DK | ,(loop [] (recur)) |
| 16:55 | Lau_of_DK | ,(loop [] (recur)) |
| 16:55 | Lau_of_DK | ,(loop [] (recur)) |
| 16:55 | clojurebot | Execution Timed Out |
| 16:55 | clojurebot | 3 |
| 16:55 | Lau_of_DK | Muhaha :) |
| 16:55 | clojurebot | Execution Timed Out |
| 16:55 | hiredman | Lau_of_DK: I will make clojurebot ignore you |
| 16:55 | clojurebot | Execution Timed Out |
| 16:56 | chessguy | ,(do 2 (+ 1 2)) |
| 16:56 | Lau_of_DK | Fine - its your bot |
| 16:56 | clojurebot | Execution Timed Out |
| 16:56 | hiredman | I'm just saying, chillax |
| 16:56 | clojurebot | Execution Timed Out |
| 16:56 | clojurebot | 3 |
| 16:56 | hiredman | do evals the forms and returns the last one |
| 16:56 | chessguy | oh |
| 16:56 | chessguy | ,(do (+ 1 2) 2) |
| 16:56 | clojurebot | 2 |
| 16:57 | hiredman | ,(do (println 1) 2) |
| 16:57 | clojurebot | 2 |
| 16:57 | chessguy | so it's intended for side effects |
| 16:57 | clojurebot | 1 |
| 16:57 | clojurebot | it is too |
| 16:57 | hiredman | erm |
| 16:57 | hiredman | not always |
| 16:57 | hiredman | it is useful in macros |
| 16:58 | hiredman | because macros can only return one form |
| 16:58 | hiredman | so you wrap a bunch of forms in a do |
| 16:58 | hiredman | like I do with pl |
| 16:58 | chessguy | interesting |
| 17:01 | slashus2 | Do zippers make it easy to write tree data structures? (e.g. red-black, b-tree) |
| 17:02 | chessguy | they're more for traversing such structures |
| 17:03 | qwert666 | have any of you seen any proj. in GSoC with Clojure ? |
| 17:03 | qwert666 | GoogleSummerofCode * |
| 17:03 | slashus2 | It seems like it would work with modifying a tree structure too. |
| 17:09 | hiredman | someone should do a soc on the function interface and the compiler |
| 17:09 | hiredman | as in, propagating type information |
| 17:22 | chessguy | so if i want to start playing with some basic existing lisp code, is the defn vs define/lambda stuff going to be the only real difference? |
| 17:22 | chessguy | (at first) |
| 17:22 | duncanm | chessguy: there are other syntactic differences |
| 17:22 | chessguy | ones that i'll run into immediately? |
| 17:22 | duncanm | chessguy: when you refer to DEFINE, are you talking about Scheme? |
| 17:22 | antifuchs | also, things like not being allowed to modify local variables after they were bound |
| 17:22 | chessguy | yes |
| 17:22 | hiredman | clojure doesn't have cons cells |
| 17:22 | hiredman | no car and cdr |
| 17:22 | duncanm | so substitute that with first and rest |
| 17:22 | chessguy | oh right, it's first and rest, right? |
| 17:22 | chessguy | yeah |
| 17:22 | chessguy | ,(rest '(1 2 3 4)) |
| 17:22 | duncanm | chessguy: the LET syntax is different |
| 17:22 | clojurebot | (2 3 4) |
| 17:22 | chessguy | ,(rest (rest '(1 2 3 4)) |
| 17:22 | clojurebot | EOF while reading |
| 17:22 | hiredman | but, if you are watching SICP, they uses cons cells for stuff like rational numbers |
| 17:22 | antifuchs | also, the cond syntax. and reader differences. check out the lisp differences page on the wiki (: |
| 17:22 | hiredman | of course clojure has rational numbers built in |
| 17:22 | chessguy | ,(rest (rest '(1 2 3 4))) |
| 17:22 | clojurebot | (3 4) |
| 17:22 | duncanm | hiredman: so does scheme |
| 17:22 | chessguy | hiredman: but using built-in code is no fun :) |
| 17:23 | hiredman | so you would use a struct for rational numbers in clojure |
| 17:23 | chessguy | a struct? |
| 17:23 | hiredman | ,(doc defstruct) |
| 17:23 | clojurebot | "([name & keys]); Same as (def name (create-struct keys...))" |
| 17:23 | hiredman | it is a kind of map |
| 17:23 | chessguy | you couldn't just use a list of 2 elements? |
| 17:23 | hiredman | optimized for making a small number of keys |
| 17:23 | Chousuke | uh, why would you use a struct? |
| 17:24 | hiredman | chessguy: you could |
| 17:24 | hiredman | if you where going to go the positional route I would use a vector |
| 17:24 | Chousuke | I wonder what the class name was though |
| 17:24 | hiredman | instead of a list |
| 17:24 | Chousuke | ,(Ratio. 1 2) |
| 17:24 | clojurebot | java.lang.IllegalArgumentException: Unable to resolve classname: Ratio |
| 17:24 | Chousuke | (class 1/2) |
| 17:24 | hiredman | Chousuke: yes yes, the native rationals was covered |
| 17:24 | Chousuke | ,(class 1/2) |
| 17:24 | clojurebot | clojure.lang.Ratio |
| 17:25 | hiredman | but, if you where making your own rationals |
| 17:25 | duncanm | i think the name is rationalize |
| 17:25 | duncanm | ,(rationalize 0.5) |
| 17:25 | clojurebot | 1/2 |
| 17:25 | duncanm | ,1/2 |
| 17:25 | clojurebot | 1/2 |
| 17:25 | duncanm | you don't need an explicit constructor |
| 17:25 | chessguy | ,(defn test ((defn numer first) (defn denom [x] (first (rest x)) (denom '(1 2))) |
| 17:25 | clojurebot | EOF while reading |
| 17:25 | chessguy | ,(defn test ((defn numer first) (defn denom [x] (first (rest x)) (denom '(1 2)))) |
| 17:25 | clojurebot | EOF while reading |
| 17:25 | hiredman | ,(struct (create-struct :denom :nom) 1 2) |
| 17:25 | clojurebot | {:denom 1, :nom 2} |
| 17:25 | chessguy | ah the fun of balancing parens |
| 17:26 | Chousuke | chessguy: def and defn won't work with clojurebot |
| 17:26 | duncanm | chessguy: use a real editor |
| 17:26 | hiredman | chessguy: I will stop you there |
| 17:26 | hiredman | no defs in clojurebot |
| 17:26 | chessguy | oh |
| 17:26 | duncanm | hiredman: just use LET! ;-) |
| 17:26 | chessguy | well poo |
| 17:26 | Chousuke | and instead of rest you want to use second anyway |
| 17:27 | hiredman | and use a struct |
| 17:27 | hiredman | :P |
| 17:27 | chessguy | ,(second '(1 2 3)) |
| 17:27 | clojurebot | 2 |
| 17:27 | duncanm | (rest '(1 2)) -> '(2); (second '(1 2)) -> 2 |
| 17:27 | duncanm | a common mistake |
| 17:27 | hiredman | USE A STRUCT |
| 17:27 | Chousuke | (let [numer first denom second] (denom [1 2])) |
| 17:27 | Chousuke | hiredman: why, though? |
| 17:27 | hiredman | a struct as clearly labeled parts |
| 17:27 | chessguy | duncanm: i was doing (first (rest x)), not (rest x) |
| 17:27 | hiredman | instead of just a list of numbers |
| 17:28 | duncanm | then that's the same as CADR, which is SECOND |
| 17:28 | chessguy | duncanm: yes, but it's not wrong |
| 17:29 | hiredman | so when you see (8 7) is that a rational? {:denominator 8 :nominator 7} is pretty clear |
| 17:29 | Chousuke | I wonder why this is being discussed as native support for rationals exists :P |
| 17:29 | chessguy | hiredman: i understand that. i'm trying to grok list syntax right now |
| 17:29 | chessguy | chillax :) |
| 17:30 | Chousuke | you wouldn't use lists for rationals anyway. you'd use vectors. |
| 17:30 | hiredman | Chousuke: because in the SICP videos they make their rationals |
| 17:30 | Chousuke | lists are overrated. |
| 17:30 | chessguy | people, I'M NOT BUILDING A RATIONAL NUMBER LIBRARY |
| 17:30 | chessguy | geez |
| 17:30 | hiredman | 14:22 hiredman : if you where going to go the positional route I would use a vector |
| 17:31 | duncanm | la la la |
| 17:38 | chessguy | well, i'm glad we got that settled |
| 17:43 | hiredman | ,(alter-meta! *ns* assoc :killroy-was-here (Date.)) |
| 17:43 | clojurebot | {:killroy-was-here #<Date Sun Mar 29 14:41:43 PDT 2009>, :a 1} |
| 17:43 | cmvkk | ^*ns* |
| 17:43 | cmvkk | ,^*ns* |
| 17:43 | clojurebot | {:killroy-was-here #<Date Sun Mar 29 14:41:43 PDT 2009>, :a 1} |
| 17:44 | antifuchs | haha |
| 17:44 | cmvkk | ,(alter-meta! + assoc :foo 2) |
| 17:44 | clojurebot | java.lang.ClassCastException: clojure.core$_PLUS___3313 cannot be cast to clojure.lang.IReference |
| 17:44 | cmvkk | ,(alter-meta! #'+ assoc :foo 2) |
| 17:44 | clojurebot | {:foo 2, :ns #<Namespace clojure.core>, :name +, :file "core.clj", :line 569, :arglists ([] [x] [x y] [x y & more]), :inline-arities #{2}, :inline #<core$fn__3310 clojure.core$fn__3310@ac0f75>, :doc "Returns the sum of nums. (+) returns 0."} |
| 17:45 | chessguy | i'm beginning to think that clojure might be the language that finally lures me away from haskell |
| 17:45 | cmvkk | wait does doc operate off of the meta |
| 17:45 | Chousuke | yes |
| 17:45 | hiredman | "hey man, I left you message in +'s metadata" |
| 17:45 | cmvkk | ,(alter-meta! #'+ assoc :doc "Subtracts two numbers. Just kidding.") |
| 17:45 | clojurebot | {:foo 2, :ns #<Namespace clojure.core>, :name +, :file "core.clj", :line 569, :arglists ([] [x] [x y] [x y & more]), :inline-arities #{2}, :inline #<core$fn__3310 clojure.core$fn__3310@ac0f75>, :doc "Subtracts two numbers. Just kidding."} |
| 17:45 | cmvkk | ,(doc +) |
| 17:45 | clojurebot | "([] [x] [x y] [x y & more]); Subtracts two numbers. Just kidding." |
| 17:45 | Chousuke | :) |
| 17:45 | cmvkk | excellent. |
| 17:45 | chessguy | haha |
| 17:46 | chessguy | ,(+) |
| 17:46 | clojurebot | 0 |
| 17:46 | chessguy | ,(+ 3) |
| 17:46 | clojurebot | 3 |
| 17:46 | chessguy | cute |
| 17:46 | chessguy | i like that syntax |
| 17:46 | AWizzArd | chessguy: in the end you could write your own reader and get any syntax you like |
| 17:46 | hiredman | huh |
| 17:47 | hiredman | never noticed :inline and :inline-arities |
| 17:47 | slashus2 | Are there any good examples of using zippers to create a tree structure? |
| 17:47 | chessguy | so i can do (defn foo [x] (...)) and then also do (defn foo [x y] (...)) ? |
| 17:47 | chessguy | slashus2: they're not used to create trees |
| 17:47 | hiredman | no |
| 17:47 | chessguy | slashus2: they're used to define them |
| 17:47 | chessguy | err |
| 17:47 | chessguy | traverse them |
| 17:48 | hiredman | you do (defn foo ([x] ...) ([x y] ...)) |
| 17:48 | chessguy | oh ok |
| 17:48 | slashus2 | chessguy: It has the ability to create new nodes and edit them. |
| 17:48 | cmvkk | man whenever you write ellipses it shows up as random gibberish in my terminal |
| 17:48 | hiredman | cmvkk: because I use a unicode ellipse |
| 17:49 | cmvkk | yep. do you have a button assigned to it or something |
| 17:49 | Chousuke | cmvkk: set up your client to use UTF-8 :) |
| 17:49 | cmvkk | my client is aterm :/ |
| 17:49 | hiredman | irssi turns ... into ... |
| 17:49 | Chousuke | well aterm ought to work. |
| 17:49 | hiredman | bah |
| 17:49 | hiredman | "..." |
| 17:49 | Chousuke | nah. |
| 17:49 | slashus2 | It has insert-child, make-node, etc. I don't see any reason why it could not be used for that purpose. |
| 17:49 | Chousuke | mine shows it just fine |
| 17:49 | cmvkk | aterm isn't unicode compatable. or so it seems...i'm running irssi on screen on aterm, and i get the weird gibberish |
| 17:49 | clojurebot | it is too |
| 17:50 | hiredman | I use terminator (tiling temrinal thing) screen and irssi |
| 17:50 | hiredman | cmvkk: each of those things has it's own unicode settings |
| 17:50 | Chousuke | cmvkk: do you have your locale set to UTF-8 |
| 17:50 | cmvkk | ............maybe |
| 17:51 | cmvkk | LANG=en_US.UTF-8 does that count |
| 17:52 | hiredman | http://jerakeen.org/blog/2005/06/screen-irssi-utf8/ |
| 17:53 | slashus2 | chessguy: Huet's paper states that changes, insertion, and deletion are valid operations. |
| 17:54 | hiredman | ... |
| 17:54 | hiredman | ? |
| 17:55 | hiredman | � |
| 17:55 | cmvkk | nope. hmm. |
| 17:55 | cmvkk | i restarted with screen -U and put /set term_charset utf-8 |
| 17:55 | cmvkk | oh well! |
| 17:55 | chessguy | ok, so why does this blow the stack? (defn foo ([] 0) ([x & rest] (+ x (foo rest)))) |
| 17:55 | hiredman | what do they show up as? squares? |
| 17:55 | cmvkk | a with a mark above it, dotted square, broken pipe |
| 17:56 | hiredman | you will never get to ([] 0) |
| 17:56 | chessguy | why? rest can't match against an empty list? |
| 17:56 | hiredman | you most likely want (apply foo rest) |
| 17:56 | hiredman | [] is not an empty list |
| 17:56 | cmvkk | chessguy that's not an empty list, it's no arguments |
| 17:56 | hiredman | it is no args |
| 17:56 | chessguy | err, whoops |
| 17:57 | hiredman | ,(doc apply) |
| 17:57 | clojurebot | "([f args* argseq]); Applies fn f to the argument list formed by prepending args to argseq." |
| 17:57 | chessguy | what's that * notation? |
| 17:57 | hiredman | * is just used there to mean more then one thing |
| 17:57 | cmvkk | it means like 'zero or more' |
| 17:57 | hiredman | it isn't language syntax |
| 17:57 | cmvkk | it's a kleene star! |
| 17:58 | chessguy | ok, typical regex-ish notation |
| 17:58 | hiredman | ,(apply + 1 2 '(3 4 5)) |
| 17:58 | clojurebot | 15 |
| 17:58 | chessguy | yeah, this seems to work: |
| 17:58 | chessguy | (defn foo ([] 0) ([x & rest] (+ x (apply foo rest)))) |
| 17:59 | hiredman | ,(apply + '()) |
| 17:59 | clojurebot | 0 |
| 17:59 | chessguy | ,(+) |
| 17:59 | clojurebot | 0 |
| 17:59 | chessguy | :) |
| 17:59 | AWizzArd | chessguy: while it works it would probably not be code that gets used in production |
| 17:59 | clojurebot | it is too |
| 17:59 | AWizzArd | ,(*) |
| 17:59 | clojurebot | 1 |
| 17:59 | chessguy | AWizzArd: uh, this is the first code i've written in clojure. i don't expect it to get used in production :) |
| 17:59 | hiredman | clojurebot: botsnack |
| 17:59 | clojurebot | thanks; that was delicious. (nom nom nom) |
| 18:00 | chessguy | so helpful for you to point that out though |
| 18:00 | chessguy | i was really concerned |
| 18:00 | AWizzArd | (defn foo [numbers] (apply + numbers)) could do the trick |
| 18:00 | chessguy | AWizzArd: so would (defn foo (+)) |
| 18:01 | chessguy | that's hardly the point |
| 18:01 | AWizzArd | No, that would not work |
| 18:01 | AWizzArd | even (def foo +) would not be the same thing |
| 18:02 | cmvkk | ,(let [foo +] (foo 2 3)) |
| 18:02 | clojurebot | 5 |
| 18:02 | AWizzArd | ,(let [foo +] (foo '(2 3)) |
| 18:02 | clojurebot | EOF while reading |
| 18:02 | AWizzArd | ,(let [foo +] (foo '(2 3))) |
| 18:02 | clojurebot | java.lang.ClassCastException |
| 18:03 | AWizzArd | ,(apply + '(2 3)) |
| 18:03 | clojurebot | 5 |
| 18:03 | chessguy | interesting |
| 18:03 | cmvkk | ,(let [foo #(apply + %)] (foo '(2 3))) |
| 18:03 | clojurebot | 5 |
| 18:03 | chessguy | not sure i get why (defn bar +) doesn't work |
| 18:04 | cmvkk | (def bar +) would just make bar work like +. |
| 18:04 | chessguy | oh right, def |
| 18:04 | chessguy | that's what i meant |
| 18:06 | chessguy | wouldn't bar then represent the same function that + represents? |
| 18:06 | cmvkk | yes. |
| 18:06 | chessguy | cool :) |
| 18:07 | chessguy | i did learn something from SICP |
| 18:07 | AWizzArd | And apply is one of those funny functions that one can not write on the same level on which one is writing the rest of the program. Although antifuchs made a nice macro that can fake apply for most practical cases ;) |
| 18:09 | chessguy | hm. so you can't evaluate clojure in clojure? |
| 18:09 | AWizzArd | you can |
| 18:09 | chessguy | hm |
| 18:09 | cmvkk | i'm not sure what you mean, though. apply isn't a special form; it's written in clojure. |
| 18:10 | astor | Thinking about the problem I mentioned earlier, a macro - (loop-seq sequence bindings &body) could be imagined which will go through a sequence and where bindings is used to keep state and where the exit of the loop is a (cons...). It seem that this macro is very hard to implement since there is not way to add extra arguments to (recur..). |
| 18:10 | chessguy | anyway, enough brain-bending for tonight. i'm off to hang out with some friends. thanks ya'all! |
| 18:10 | cmvkk | on second glance, apply is written with java after all. |
| 18:10 | AWizzArd | cmvkk: yes right.. but look at it's definition |
| 18:10 | AWizzArd | yup |
| 18:11 | AWizzArd | just write your own apply without making use of apply itself |
| 18:12 | cmvkk | (defmacro myapply [f args] `(~f ~@args)) |
| 18:12 | cmvkk | :) |
| 18:13 | AWizzArd | yes, that works for a subset of cases where one can use apply |
| 18:15 | AWizzArd | a small subset |
| 18:15 | dnolen | ,(apply apply [+ [1 2 3]]) |
| 18:15 | clojurebot | 6 |
| 18:16 | cmvkk | my version does that too? |
| 18:17 | AWizzArd | yes |
| 18:17 | AWizzArd | but try for example: |
| 18:17 | AWizzArd | ,(range 2 4) |
| 18:17 | clojurebot | (2 3) |
| 18:17 | AWizzArd | ,(apply + (range 2 4)) |
| 18:17 | clojurebot | 5 |
| 18:17 | duncanm | ,(range 1 3) |
| 18:17 | clojurebot | (1 2) |
| 18:17 | duncanm | heh |
| 18:17 | hiredman | cmvkk: I surprised you haven't paste your lazy-loop yet |
| 18:17 | cmvkk | touche! |
| 18:18 | cmvkk | hiredman I did a long time ago |
| 18:18 | cmvkk | 1 1 0 |
| 18:18 | cmvkk | http://paste.lisp.org/display/77400 |
| 18:19 | cmvkk | it captures a variable though |
| 18:19 | clojurebot | it is too |
| 18:19 | AWizzArd | hiredman: you gave him too much botsnacks |
| 18:19 | AWizzArd | too many |
| 18:19 | Chousuke | :P |
| 18:22 | cmvkk | astor: look at my paste above |
| 18:22 | cmvkk | didn't notice that you were looking for something like that |
| 18:22 | clojurebot | for is not used often enough. |
| 18:22 | cmvkk | ideally you'd want a structure that you can either recur OR give, so that you can 'skip' iterations. |
| 18:23 | cmvkk | this is something that streams would be able to do i think? |
| 18:23 | hiredman | I think you can do it with seqs |
| 18:23 | hiredman | you just return a call instead of a cons |
| 18:23 | cmvkk | in theory |
| 18:24 | cmvkk | right, but then you have to start worrying about blowing the stack if you skip too many times. |
| 18:24 | cmvkk | you can't use recur, since that won't work through a lazy-seq. |
| 18:24 | cmvkk | actually, you can't just call either. becuase then you have a lazy-seq returning another lazy-seq. |
| 18:24 | cmvkk | which isn't quite right... |
| 18:25 | cmvkk | actually, the way to do it would be to expand a loop right inside the lazy-seq, that just binds the same arguments as the function as a whole. |
| 18:25 | cmvkk | then you can use recur normally, and if all you do is return a cons right away, it just ignores the loop entirely. |
| 18:30 | lisppaste8 | cmvkk annotated #77400 "fixed lazy-loop" at http://paste.lisp.org/display/77400#1 |
| 18:45 | astor | cmvkk: inspired by lazy-loop, I wrote a very simple lazy-seq-fn |
| 18:45 | Chousuke | what does that do? |
| 18:45 | lisppaste8 | astor annotated #77400 "lazy-seq-fn" at http://paste.lisp.org/display/77400#2 |
| 18:47 | lisppaste8 | astor annotated #77400 "untitled" at http://paste.lisp.org/display/77400#3 |
| 18:48 | astor | an fn where I can use either recur or cons based on whether I want to filter or not. |
| 18:50 | astor | adding support for destructuring in bindings requires "slightly" more work :-) |
| 18:50 | Chousuke | (doc destructure) |
| 18:50 | clojurebot | excusez-moi |
| 18:50 | Chousuke | hm |
| 18:50 | cmvkk | my fixed lazy-loop does that, though. |
| 18:50 | Chousuke | anyway, there's a function that destructures a binding form |
| 18:50 | cmvkk | you can 'recur' or 'give' based on whether you want to skip or not, and it supports destructuring the same way regular loop does. |
| 18:51 | Chousuke | ,(destructure '[x 1 y 2]) |
| 18:51 | clojurebot | [x 1 y 2] |
| 18:51 | Chousuke | eh |
| 18:51 | Chousuke | I'm silly sometimes |
| 18:51 | Chousuke | ,(destructure '[[x y] [1 2]]) |
| 18:51 | clojurebot | [vec__4374 [1 2] x (clojure.core/nth vec__4374 0 nil) y (clojure.core/nth vec__4374 1 nil)] |
| 18:53 | durka42 | oh, that's how it works |
| 18:53 | durka42 | cool |
| 18:53 | cmvkk | ,(doc destructure) |
| 18:53 | clojurebot | "([bindings]); " |
| 18:53 | astor | cmvkk: the (vector % %) doesn't work with destructuring. |
| 18:53 | Chousuke | it's undocumented :) |
| 18:53 | cmvkk | astor... hmm, you might be right. |
| 18:54 | cmvkk | HMM. |
| 18:54 | astor | cmvkk: lazy-seq-fn does not have the capture problems. I think it captures the essence of your idea. |
| 18:55 | cmvkk | yep, it's pretty much the same thing. |
| 18:55 | cmvkk | now i'm just wondering how to fix destructuring on both of them. |
| 18:56 | Chousuke | actually, since loop supports destructuring, wouldn't calling that with something like [x [y z]] end up like (loop [x x [y z] [y z]] that is completely valid? :/ |
| 18:57 | cmvkk | the problem is when you get [[x & y :as z] [x & y :as z]] where clearly the second is not a valid initial form. |
| 18:57 | Chousuke | ah, true. |
| 18:58 | cmvkk | aha, i know how to do it. |
| 18:59 | cmvkk | for the function's arglist, you just use gensyms. then for the loop, you use the actual destructed args, and the gensyms as the inits. |
| 18:59 | astor | cmvkk: nice |
| 19:02 | lisppaste8 | cmvkk annotated #77400 "double fixed lazy-loop" at http://paste.lisp.org/display/77400#4 |
| 19:36 | hiredman | http://boinkor.net/archives/2009/03/clojure_and_art_of_illusion_bf.html <-- awesome |
| 19:36 | qwert666 | hmm i`m using the fibonacci code from http://clojure.org/atoms and with a large numbers i`m getting StackOverflowError do u know any "tricks" to omit the stack problem... ? |
| 19:36 | cmvkk | even with the memoization? |
| 19:37 | hiredman | it depends what is blowing the stack, and how large your numbers are |
| 19:38 | cmvkk | ah yeah, it would. |
| 19:38 | qwert666 | hiredman: fib >500 |
| 19:38 | cmvkk | because if you start it out, it still has to call back and memoize every single previous number. |
| 19:38 | Puzzler | yeah, that implementation would blow the stack. |
| 19:39 | hiredman | I have no idea how big that number is |
| 19:39 | cmvkk | hiredman, it doesn't matter how big the result is. |
| 19:39 | clojurebot | it is too |
| 19:39 | qwert666 | hmm so the implementation sux for big numbers :( |
| 19:40 | Puzzler | Some other versions of Scheme / Lisp don't really have a stack that's limited by anything but overall memory, but in Clojure, you've got to be careful, because it's running on Java. |
| 19:40 | cmvkk | yeah, even if you memoize that's a really bad way to write a fibonacci algorithm. |
| 19:40 | cmvkk | i think this sort of recurring is likely to blow the stack no matter what language you use. |
| 19:42 | qwert666 | mhm ok thx u`r probably right |
| 19:42 | dnolen | Puzzler: that's not completely true, Scheme & Lisp have TCO, you can still blow the stack. |
| 19:42 | dnolen | Scheme & CL I meant. |
| 19:43 | hiredman | from what I hear not all CL impls have tco |
| 19:43 | Puzzler | I don't know the implementation details, but I've used PLT Scheme enough to say that function calls are not implemented using a limited stack that can "blow". Eventually, you'll run out of overall memory on your machine, but far after mainstream languages would blow a stack. |
| 19:43 | dnolen | hiredman: you are correct. |
| 19:44 | Puzzler | It's as if everything is heap allocated (don't know if that's really how it's implemented, though). |
| 19:44 | dnolen | Puzzler: they will blow if the recursion calls are not in the tail posiitin. |
| 19:44 | cmvkk | Puzzler, are you sure you aren't thinking of tail recursion? |
| 19:44 | cmvkk | yeah. |
| 19:45 | Puzzler | I'm sure. Yes, I know the memory will eventually run out. I'm just saying it is not as limited as languages which have a very small amount of memory set aside for stack. |
| 19:45 | Puzzler | You can do non-recursive things involving many thousands of levels deep, and it won't bat an eye. |
| 19:45 | dnolen | in Clojure you can do pretty much the same thing with trampolines or recur |
| 19:45 | dnolen | Puzzler: you can set the stack memsize to the jvm instanc.e |
| 19:45 | Puzzler | I meant "non tail-recursive" |
| 19:46 | dnolen | Puzzler: that's because functions calls are in the tail position. |
| 19:46 | cmvkk | dnolen, that wouldn't be "non tail-recursive" though. |
| 19:46 | Puzzler | To put it in perspective, in Clojure, you have to be very careful about writing non tail-recursive traversals of really long lists (like simple implementation of map). |
| 19:47 | Puzzler | In PLT Scheme, if the list can fit in your memory, you'll have no problem with the accumulated function calls fitting in memory too. So basically, you can write your function in the naive way, without worrying about stack. |
| 19:48 | Puzzler | That's cause in most languages the stack is only a small percentage of overall memory. |
| 19:48 | dnolen | cmvkk: the TCO, is tail call optimization, recursion is one case as far I understand the issue. |
| 19:48 | cmvkk | but i think his point is that PLT scheme won't blow the stack, even if you don't take advantage of TCO. |
| 19:49 | cmvkk | you can have recursion without having TCO. |
| 19:50 | Puzzler | Right cmvkk, you'll eventually run out of memory, but after you've used all 3GB of RAM on your machine (not likely to happen), rather than after 3000 function calls deep, or some other arbitrary number. |
| 19:51 | cmvkk | although that might be the case, i don't think it makes it okay to write naive recursive algorithms |
| 19:51 | cmvkk | you're right though: "At the same time, recursion does not lead to particularly bad performance in Scheme, and there is no such thing as stack overflow;" |
| 19:51 | cmvkk | from the PLT docs |
| 19:52 | Puzzler | Consider something like this: (defn map [f s] (if (empty? s) () (cons (f (first s)) (map f (rest s)))) |
| 19:53 | Puzzler | In PLT Scheme, you don't have to worry about stack overflow. But you do in Clojure. |
| 19:53 | Puzzler | An easy fix in Clojure is to wrap this in a lazy-seq. |
| 19:53 | cmvkk | it's still a bad idea to do that, though. |
| 19:53 | Puzzler | Why? |
| 19:53 | cmvkk | in fact, that's how map is defined in clojure... |
| 19:53 | cmvkk | because TCO is more efficient in general |
| 19:53 | qwert666 | so if i`m geting it right... the TCO secure in some way the jvm from blowing the stack off... ? |
| 19:53 | Puzzler | But for other kinds of traversals, it's not such an easy fix. |
| 19:54 | cmvkk | and because using O(n) space is pointless if you can do it in constant space. |
| 19:54 | cmvkk | "Similarly, in Scheme, it is often important to make sure that tail recursion is used to avoid O(n) space consumption when the computation is easily performed in constant space." |
| 19:54 | cmvkk | also from the PLT docs. |
| 19:55 | Puzzler | You're going to use up O(n) space anyway to build the final list. Taking up the same amount of space, temporarily, with "stack"-like allocations, doesn't change anything. |
| 19:55 | cmvkk | I suppose that's true...except for the extra function call stuff, I guess. |
| 19:56 | Puzzler | You can't easily make map tail-recursive without reversing the list, and reversing it again at the end (or using laziness which adds its own overhead). |
| 19:57 | Puzzler | Amazingly, if you compare a tail-recursive and non-tail-recursive version of factorial in PLT Scheme, the non-tail-recursive one is faster. |
| 19:57 | cmvkk | Yeah, the docs seem to suggest that that's the case. |
| 19:57 | dnolen | hey I just tried factorial in DrScheme and I ran out of memory, (fact 10000000) |
| 19:57 | cmvkk | heh |
| 19:57 | cmvkk | i think that kind of input doesn't prove much... |
| 19:58 | Puzzler | My guess is that with that kind of input, the final answer is too big to fit in memory :) . |
| 19:58 | lisppaste8 | dnolen pasted "scheme blow stack" at http://paste.lisp.org/display/77760 |
| 19:58 | dnolen | i don't think that is true Puzzler |
| 19:58 | dnolen | the problem here is that the call to fact is not in the tail position |
| 19:59 | dnolen | the stack grows because of the * |
| 19:59 | cmvkk | yep. it's not *impossible* to blow the stack in PLT, but you have to run out of all memory. |
| 19:59 | cmvkk | to calculate that number, you need ten million stack frames... |
| 20:00 | Puzzler | Yes, what cmvkk said is exactly my point. |
| 20:00 | dnolen | the point is that code cannot be TCO'ed |
| 20:00 | dnolen | the multiply needs the stack to grow to resolve all values. |
| 20:00 | Puzzler | I don't think 10 million stack frames is your limiting factor though. My guess is it's the manipulation of such enormous integers. |
| 20:01 | cmvkk | i wonder. try it again with + instead of *. |
| 20:01 | cmvkk | that won't come near running out of memory just because of the integer. |
| 20:02 | dnolen | it stills runs out of memory |
| 20:02 | dnolen | http://funcall.blogspot.com/2009/03/not-lisp-again.html |
| 20:02 | dnolen | this is not my own invention, example culled from here |
| 20:02 | dnolen | it explains the TCO issue quite well. |
| 20:02 | cmvkk | in any case, factorial is a good example of a function that nobody should be defining like that, no matter how good your language handles recursion. |
| 20:03 | cmvkk | but i think we can agree on that point... |
| 20:04 | Puzzler | OK, I concede that PLT Scheme can't handle 10,000,000 function calls deep. |
| 20:04 | dnolen | true, enuf, but it should clearly what TCO means, you need to write you code so that TCO can kick in even in Lisp and Scheme. |
| 20:04 | cmvkk | dnolen, well, to be fair, probably nobody's going to calling factorial ten million. |
| 20:05 | cmvkk | factorial's just an example of a function that's it's really simple to write in tail position. |
| 20:05 | Puzzler | It still helps that you're not as limited as in most languages. |
| 20:05 | cmvkk | no, you're right. especially with functions that hare hard to make tail-recursive. |
| 20:05 | Puzzler | When I write recursion over lists or trees, I do worry about whether Clojure will be able to handle the depth. |
| 20:06 | Puzzler | I'm not used to worrying about that. |
| 20:06 | Puzzler | I'm working on code right now that can't really be trampolined or turned into TCO, but potentially has a fair amount of depth. |
| 20:06 | cmvkk | it's a problem when you do tree recursion. since trampolines only work on tail calls too... |
| 20:07 | Puzzler | I'd probably have to do something analogous to lazy-seq, storing a delay to the next node of the tree. |
| 20:08 | Puzzler | Fortunately, the stack limitation hasn't bitten me yet on this particular code, but it bothers me that it is fragile in this respect. |
| 20:10 | qwert666 | i`m searching for some benchmarks results of clojure and other langs do you know any good source of info. ? i usually was using http://shootout.alioth.debian.org/ but no clojure code there :( |
| 20:10 | Puzzler | Hmmm, I wonder if there is a clever way to use futures to return immediately, like a delay, but continue building the tree immediately on a separate thread. |
| 20:11 | Puzzler | I haven't seen much benchmarking of Clojure. |
| 20:11 | Puzzler | I have been impressed with its speed overall. |
| 20:12 | Puzzler | I LOVE the persistent vectors. |
| 20:16 | qwert666 | Puzzler: ye but i think it would beat few langs anyway :) and it would be nice to compare the speedup of clojure from a perspective of time |
| 20:22 | qwert666 | Puzzler: i think that the fib example from clojure is quite good |
| 20:22 | qwert666 | 0.044ms for fib 35 |
| 20:30 | dnolen | Puzzler: you are right about tree walking it does present a problem in Clojure, that's where tree-seq helps. |
| 20:30 | dnolen | ,(doc tree-seq) |
| 20:30 | dnolen | clojurebot kaput? |
| 20:30 | clojurebot | "([branch? children root]); Returns a lazy sequence of the nodes in a tree, via a depth-first walk. branch? must be a fn of one arg that returns true if passed a node that can have children (but may not). children must be a fn of one arg that returns a sequence of the children. Will only be called on nodes for which branch? returns true. Root is the root node of the tree." |
| 20:42 | Puzzler | I haven |
| 20:42 | Puzzler | I haven't played around much with tree-seq. |
| 20:42 | Puzzler | I think I need a convenient, lazy way to *construct* trees, however. |
| 21:38 | Raynes | I usually feed off of Clojure Swing examples but it seems virtually no one has used JPopupMenu within Google Space. |