#clojure logs

2008-07-26

01:55jykrdhi
01:56jykrdI'm trying to figure out how to convert java into clojure. As an exercise, I'm trying to convert this: http://www.devdaily.com/java/edu/pj/pj010016/pj010016.shtml
01:56jykrd(runs system commands)
01:57jykrdAnd to go off of, I'm trying to glean the method from the gui example on the wiki
01:58jykrdso the first thing I did was converted this: Process p = Runtime.getRuntime().exec("ps -ef");
01:58jykrdto this: #^Process p (. (. (Runtime getRuntime) exec (str "ps -ef")))
01:59jykrd(inside a let)
01:59jykrdBut I get the feeling that's not the correct way
02:00jykrdI'm not worried about the str so much.. more so the #^Process at the beginning
02:05mebaran151I think you can drop that
02:05mebaran151clojure does a little bit of type inference
02:06jykrdso does Runtime.getRuntime() always return a Process? I was figuring that line was doing type casting, or casting to the super, or something
02:06jykrdWould have expected to see Runtime p = Runtime.getRuntime()
02:07mebaran151I'm not super familiar with that call
02:07jykrdok
02:07mebaran151but yeah, I suppose if the javadocs say so it must be true
02:07jykrdwell, from the repl, that compiles, so I guess I'll keep trucking
02:08mebaran151I think it just takes those comments as hints though
02:08mebaran151so even if you were wrong, it would valiantly try
02:08jykrdnow, to do this in a let : BufferedReader stdInput = new BufferedReader(new
02:08jykrd InputStreamReader(p.getInputStream()));
02:08mebaran151I hate how long java names are
02:09jykrdwould is there a more graceful way than: stdinput (new BufferedReader (new InputStreamReader (. p getInputStream)))
02:10mebaran151not in java land
02:10jykrdok.. Well that might work then
02:10mebaran151but I don't think it would be much more graceful in java anway
02:10jykrdwell, I mean, in clojure, is there a better way than calling a new withing a new
02:13mebaran151you can use doto for a lot of this
02:13mebaran151oh yeah
02:13mebaran151ClassName.. make work
02:13mebaran151I think I saw that in the docs
02:13mebaran151it's a macro that automagically instantiates that class
02:14jykrdhuh
02:14jykrdit works
02:18jykrdYou know what they need in the docs, under the "clojure for java people" section.. is a "converting a 'while' structure into clojure" and the like
02:22mebaran151yeah I'm using it for a cool webstartup that's partially written in scala
02:22mebaran151it would be really nice if the docs weren't so non-existent
02:23mebaran151or at least if they could wiki the doc section so we could add comments
02:23mebaran151you wouldn't use a while loop in clojure thouhg: it's not very functional
02:23mebaran151what are you trying to do
02:23mebaran151usually map or reduce will get you 90 percent there....
02:24jykrdtrying to do:
02:24jykrd while ((s = stdInput.readLine()) != null) {
02:24jykrd System.out.println(s);
02:24jykrd }
02:25mebaran151reading a file eh
02:26mebaran151I've never really understood how do that functionally but we could write a monster hybrid for kicks
02:26jykrdAnd I'm actually thinking: (loop [s (. stdInput readLine)]
02:26jykrd (when-not (= s nill)
02:26jykrd (.. System out (println (str s)))))
02:26jykrdstd input
02:26mebaran151I think loop is only for recur
02:27jykrdoh yea, and I'd have to add a recur at the end I guess
02:27mebaran151you could do something using
02:27jykrdwith the same condition as when-not or something
02:27mebaran151(repeatedly (. stdInput (readline))
02:27jykrdhmm
02:27mebaran151that builds a lazy list of readlines
02:27jykrdreally?
02:27mebaran151yeah
02:27mebaran151cloisng the file might be problematic though
02:28mebaran151if you close the file and try to run that
02:28jykrdits std input, not a file
02:28mebaran151some sort of exception has to be thrown
02:28mebaran151stdinput my bad
02:28jykrdyou remember which doc page the repeatedly was on?
02:28mebaran151the api is all doc'ed alpabetically
02:28mebaran151do a search text in firefox for lazy
02:29mebaran151and you'll find a lot of cool macros rick wrote
02:30jykrdgah, it's all so terse
02:33jykrdso, (repeatedly (.. System out (println (. stdInput (readline))))
02:33jykrdor something?
02:39jykrdgah.. looping control structures.. I'm having such a hard time wrapping my head around them in a functional way
02:40mebaran151yeah
02:40mebaran151io is not the best place to learn about fp
02:42mebaran151it would more like be something like
02:44mebaran151repeatedly (fn [] (.. System (println (.stdInput (readline))
02:50jykrdeeeoooh
02:56mebaran151you might put some more conditional logic in there
02:56mebaran151to represent each iteration
02:57jykrdyea, it's flooding the screen with nills
02:57mebaran151oh yeah
02:57mebaran151don't directly type in repeatedly
02:57mebaran151it will try to evaluate it fully
02:57mebaran151you have set it equal to something
02:57mebaran151like (def lines (repeatedly what .....))
02:57mebaran151then do first and rest stuff on it
02:57jykrdhuh
02:58jykrdhmm
02:58mebaran151to print something it has to evaulate it
02:58mebaran151prn recursive tries to print everything, which fails for an infinie list
03:00mebaran151just keep a little pointer around and iterate until nil
03:01jykrdoh my gosh, it almost works :)
03:01hoeckor use (take n (repeatedly ..))
03:04jykrdwow.. I've got output
03:05jykrdI'm running the my linux' ps command from clojure ! :)
03:06jykrdnow I just need to round this out into a tool of some sort and I might be able to start doing shell scripting with clojure
03:06jykrdyou guys kick ass.. thanks.. I need to sleep now, but I'm glad I stayed up :) night
03:07mebaran151np
03:07mebaran151just looking at line-seq
03:08mebaran151I think that clojure should have some more clojurey file openers
03:09hoeckmebaran151: what about "slurp"?
03:10mebaran151isn't that only for valid clojure files though
03:10mebaran151you know
03:10mebaran151better reading and writer
03:11mebaran151and maybe some more in depth control structures
03:11mebaran151*deserializing structures
03:11mebaran151boy am I tired
03:12mebaran151also I was workng with a colleague in clojure (which we've snuck in our project via the all knowing JVM)
03:12mebaran151we think that it would be relaly nice if you guys could open the clojure api to wiki comments
03:12mebaran151sort of like php
03:13hoeckaha, i don't know much about php
03:14mebaran151I don't either
03:14mebaran151but when I had to fix one script
03:14mebaran151it was really nice that the php docs had a comment section
03:14mebaran151and other users had recorded their thoughts
03:14mebaran151spruced with a little ajax, people could note whether or not to look at the comments
03:14mebaran151sometimes the function is sort of unclear how it works, esp with things like refs and agents
03:16mebaran151the massive alphabetized list of functions is also rather unappealing: maybe some sort of tagging system to relate what their good for that people could use to sort them
03:18mebaran151also it's almost idiotic that we don't have a siimple way just to eval code and I have go through hell just to turn a string into a BufferedReader for eval like semantics
03:18hoeckyeah, the api docs are really huge and hard to search, especially if you don't know which function to search for
03:20mebaran151exactly
03:20mebaran151I'm currently writing a little object store in clojure sort of rucksack
03:20hoeckif you're on the repl, you can use (find-doc "file") to search for all functions containing "file" in their docstring
03:21mebaran151you have any suggestions, especially with regards to efficiently serializing a b* tree
03:22hoeckno, not really
03:22mebaran151it's hard to find good byte reading stuff on clojure
03:23mebaran151and I don't know much about training the interpreter to be more efficient at slurping in objects
03:24hoeckwhat kind of objects?
03:25mebaran151arbitrary hashes really
03:26mebaran151I do all the db management stuff using metadata which is really rather convenient
03:28hoecki'm still wondering for what and when to use metadata, except for docstrings and test-related stuff
03:59hoeckmebaran151: i guess rhickey is going to think about your suggestions when he is up again.
04:00hoeckjust found out that find-doc doesn't print the function name :(
04:00mebaran151I keep the original hash of the reconstructed object and its id in metadata, and using those I can determine whether I should update the object in the db or do nothing
04:00mebaran151when a call to save is made that is
04:00mebaran151I hope he does
04:01mebaran151I think clojure is a pretty cool language
04:01mebaran151that could use just a little bit more love
04:06hoeckaha, nice
04:07hoeckwhat do you use for interfacing with the db?
04:22mebaran151_I'm gonna write that back end part later
04:22mebaran151_write now
04:22mebaran151_the filesystem is doing all the heavy lifting
04:24mebaran151_for this project, I was scared over overflowing int so I decided to make my primary keys vectors of integers which would map to file paths that would each contain buckets of say 128 tiny objects could be slurped up and sliced and diced
04:27hoeckso you're using the clojure reader to read those vectors?
04:27Laurent_nickname lpetit
04:38mebaran151_hoeck: currently yes
04:39mebaran151_I'm planning on supporting a sane way to query with simple key value semantics that can be joined together or orred
04:40mebaran151_I've never found SQL very easy to grok myself
04:43hoeckmebaran151_: i learned sql by reading the documentation and source at work and by the help of my colleagues
04:43mebaran151_I know SQL, just it seems so inefficient to produce massive query strings
04:43hoeckbut got really enlightened by the relational algebra
04:44mebaran151_and much of this data is free form, so it doesn't fit in the table metaphor very well
04:45mebaran151_I know a bit of relation algebra actually. If SQL didn't seem so obsessed with covering up its relation roots
04:45mebaran151_it might be more sane to code gen it
04:46mebaran151_and I never thought it really stuck with lisp very well
04:50mebaran151_anyway I'm going to bed
04:50hoeckbut the relational algebra fits good into the lisp world, imho
04:50mebaran151_it does
04:50mebaran151_I'll agree with that
04:50mebaran151_however, far too many problems get solved with SQL aren't really relational in nature
04:51hoecka algebra->sql compiler is on my todo list :)
04:51mebaran151_and SQL doesn't do its roots justice I don't think
04:51mebaran151_it seems as though all the latest database tech is leaving the relational word
04:51mebaran151_with products like s3 and clouddb and the whole google appdb
04:52hoeckyeah, i've heard of that
04:52mebaran151_it seems as though relational logic should be done in the language itself
04:52mebaran151_with conj and disjuct operators on sets
04:52hoeckthey are more like big berkeley-dbs
04:53mebaran151_we're planning on using S3 for some stuff in our app, so it seemed logical to role our own simple query engine
04:53hoecki'm only working on a small-scale client-server insurance management application
04:54mebaran151_we're not so big yet ourselves
04:54hoeck(at work) so sql really fits that model
04:54hoeckaha
04:54mebaran151_sql is a good fit if all your data is going to look the same
04:54hoeckbut i guess its hard to roll your own query engine efficiently
04:55mebaran151_reading up on redblack trees
04:55mebaran151_which I half way remember how to implement
04:55mebaran151_there isn't too much magic to SQL systems, esp for single transactions
04:56mebaran151_you can either loop over all the blocks of the rows in O(n) or hopefully leverage a query and do your work in O(log n)
04:57mebaran151_it's handling insertion and deletion properly that normally gets ya, but I think Clojure actually provides some pretty powerful primitives along those lines
04:57mebaran151_*leverage an index
04:59mebaran151_as none of the individual queries are going to be very complex, i really doubt that there will be too much room for a normal SQL engine to optimize their order, though I could be very ver wrong
05:00hoecksometimes i'm really surprised how fast a crappy multiline sqlstatement on a long grown database schema can be
05:01mebaran151_yeah
05:01mebaran151_is there anything good in clojure world for sql mapping
05:01hoeckokay, for short queries, i guess its the index which is responsible for the speed
05:01mebaran151_cl lisp had rucksack and I looked at elephant, but didn't find much for clojure
05:02hoeckspring,hibernate :)
05:02mebaran151_most of the beneift of a big database comes from the fact the daemon can arbitrate queries and optimize the order in which they are received for locaity
05:03mebaran151_wouldn't hibernate fail though because clojure hashes aren't really classes?
05:03hoeckiirc, there was a simple jdbc->clojure thing on the mailinglist
05:03mebaran151_seems like hibernate would have to be very Java or at least class oo centric
05:04hoecki just know hibernate as a buzzword
05:05mebaran151_I've used it a little bit
05:05mebaran151_it's pretty pretty fancy
05:07hoecki never used java before, clojure was my first encounter with java
05:08hoeckbut i really like the java libs, though their use seems often over-complicated, once i have something working in clojure, i can abstract the uneccesary java-gluecode stuff away
05:08hoeckso clojure +1!
05:10mebaran151_I moved from Scala to Clojure
05:10mebaran151_sometimes I mis the static types
05:11hoeckdo you miss them for the speed you gain from static typing?
05:12msinghare places first class in clojure?
05:13mebaran151_hoeck: not for the speed, but for the way it guided my modeling
05:13mebaran151_I have to be much more disciplined as I write lisp
05:13kotarakmsingh: ehem... What is a place?
05:13mebaran151_I think clojure does a halfway decent job of coercing types
05:14msinghkotarak: not sure :)
05:14mebaran151_it's sort of like the difference between installation on a mac and on a PC: it took me forever to get used to the fact that you could just drag files to the Applications folders and everything could just work
05:15mebaran151_something about static typing makes me feel warm and fuzzy
05:16msinghyes, that's how a straight jacket feels like
05:16mebaran151_well it does catch some quick bugs and makes sure that your functions interop properly
05:17msinghnot an issue
05:17kotarakthere is a nice example, where static type checking (with inferencing) caught a infinite loop.
05:17msinghin lisp programming you test your functions as you work on them so those bugs tend to get caught by the programmer as a matter of course
05:18mebaran151_but for a current project, I want to be able to easily turn some of my functions into xml
05:18mebaran151_lisp is really really really good for that
05:18kotaraktype are another layer to transport information.
05:18hoecki like the way common-lisp provides types, for having speed where its necessary
05:18mebaran151_the JVM mostly discards your type info
05:19mebaran151_most of what I read doesn't really put too much emphasis on types
05:19hoeckyeah, on java, speed isn't such a big issue
05:19hoeckaha
05:19mebaran151_most of them can be inferred by a smart compiler (aka Hotspot) and fairly efficiently statically inlined
05:23hoecki wrote a little physics simulation in clojure, and it was as slow as hell :(
05:23hoeckcompared to the c++ demo in ran in wine
05:23mebaran151_hotspot does take awhile to warm up though
05:24mebaran151_and I don't know much about how well it vectorizes code
05:24hoeckbut it was fully dynamic, like adding objects at any time
05:25hoeckwell, it used the boxing number types in clojure, and vector-tuples, so it wasn't trimmed on speed either
05:25hoeckand it was way more fun than writing a c++ app :)
05:26mebaran151_can you tell clojure to downcast if to unboxed primitives if you know best?
05:27hoeckthere are some tweaks on unboxed array access, and on using unboxed numbers
05:29hoeckit was discussed in a group-thread about imagej
05:54mebaran151_I need to get myself on the list...
05:56hoeckclojure moves pretty fast, personally, i read the list and the clojure-log
06:05mebaran151_because otherwise, I don't see any reason why clojure objects should technically have any slower dispatch once compiled
06:05mebaran151_but I'm gonna take a na
06:05mebaran151_p
06:06mebaran151_good night all
11:47jykrd1yerrp
11:56jykrd1I've got clojure to run the ps command, so the output is like: ("UID PID PPID C STIME TTY TIME CMD" "root 1 0 0 Jul25 ? 00:00:02 /sbin/init" "root 2 0 0 Jul25 etc.
11:56jykrd1but there's no /newlines in the output
11:57jykrd1it's just one long string.
11:57jykrd1doesn't ps print a string formated with new lines?
11:57kotarakWhat you just pasted is a list of strings, each string representing one line.
11:57jykrd1and tabs
11:57rhickeythat looks like a list of strings
11:57jykrd1oh
11:58jykrd1so, lines (repeatedly (fn [] (. stdInput readLine))) is creating a list of words, rather than lines, really
11:59jykrd1er, (let [lines (repeatedly.... etc
11:59rhickeyno, it's creating a list of lines, each of which is a string
11:59kotarakI would expect it to produce, what you pasted: a list of lines
12:01rhickeyreadLine doesn't return the line terminators
12:01jykrd1right... so should I concatenate a /nl onto lines each line after it returns?
12:01rhickeydepends on your goal - what is your goal?
12:02jykrd1to make a function that can take any shell command and return it like it would in the shell, i guess
12:03rhickeyreturn a single string or print it?
12:03rhickeyprint directly: (dorun (map println ["a" "b" "c"]))
12:04rhickeyprint into a string: (with-out-str (dorun (map println ["a" "b" "c"])))
12:04rhickeyreplace ["a" "b" "c"] with your list of lines
12:44albinojykrd: fyi, I think the java sigar libs have ps in them if you wanted to call an api instead of forking a process
13:03jykrdalbino: thanks. Actually it was just an example. Was wondering if I could use Clojure for shell scripting. some kind of run-command function might help with that.
13:03jykrdseems to work
13:04kotarakHeretic, I know, but: there is also scsh which is kind of specialised on shell scripting, in case you just want something lispish.
13:05albinojykrd: It's a good use case, a lot of what I do is fork processes with my code so I would want some sort of abstraction for that
13:17shooveralbino: Just curious, what's the nature of your forking? Is it aimed at fault tolerance or just not sharing state across threads or something else?
13:20albinoshoover: getting stuff done on unix requires calling all sorts of command line utilities
13:20albinoshoover: for work I write a lot of code that automates the use of our products via command line
13:20albinoshoover: In my case it ends up being calls to subprocess.Popen in python
13:24shooveralbino: ah, ok, you're talking about good ol' shell scripting. I was getting ahead of myself thinking you were wanting the process abstraction for full-blown Clojure apps.
13:27albinoshoover: yep, no api like the command line :)
13:42mebaran151I'm gonna reiterate my proposal for wiki'izing the docs
13:42rhickeythere is a wiki, the docs are a reference
13:43mebaran151it would be nice if they weren't just a long alphabetical list
13:43rhickeythere are many pages of docs in addition to the API list
13:44mebaran151and I think certain functions could stand nice little docs
13:44mebaran151*comments
13:45mebaran151kind of the way php lets users add optional annotations and tips
13:45rhickeylink?
13:51rhickeymebaran151: hello? do you have a link for the php wiki you are recommending I emulate?
13:51mebaran151oh sorry
13:52mebaran151I have to refind it: I haven't done php in quite awhile but I remember the comment system being superb
13:54mebaran151http://www.php.net/manual/en/install.macosx.bundled.php
13:54mebaran151look at the user contributed notes section
13:54arohnerpostgres has something similar
13:54arohnerhttp://www.postgresql.org/docs/
13:54mebaran151postgres I think took the idea from the PHP people
13:55arohnerthe API section on the website is generated from the docstrings in the code, right?
13:55arohnerso it's simple enough to patch that
13:56mebaran151we could add a more human feel if we did it this way: esp when it comes to little examples for the fancy concurrency goodness that's baked in
13:56rhickeythe wikispaces I am using currently has no membership granularity - i.e. all members can edit pages and submit comments. I really don't want people editing pages. I would prefer people use the wiki and build any supplementary material they want. I've asked for examples many times - people will get out of it what they put into it
13:57rhickeyI understand the docs are not much of a tutorial
13:58mebaran151I was pretty new to LISP, but luckily alot of the scheme stuff on the internet helps out
13:58rhickeybut there needs to be an accurate reference somewhere
13:59rhickeyI've also put up many hours of talks on blip.tv
14:01mebaran151I've watched them, and they were very informative and what alerted me to clojure in the first place. However, talks are very inefficient when it comes to trying to find specific information.
14:01mebaran151you can't just search text or skim a talk
14:56jykrdI'd find it useful if someone put examples in the java section of the wiki that described conversion practices, like converting a while loop int clojure
15:30jgrantis clojure a lisp-1 dialect ?
15:31kotarakI think so.
15:31kotarakjgrant: http://clojure.org/lisps has more info on this.
15:32jgrantReally then why is this a problem ? -->
15:32jgrantClojure
15:32jgrantuser=> (defn fact[n]
15:32jgrant (if (= n 0)
15:32jgrant 1
15:32jgrant (* n (fact (- n 1)))))
15:32jgrant#'user/fact
15:32jgrantuser=> (fact 10000)
15:32jgrantjava.lang.StackOverflowError
15:32jgrantjava.lang.StackOverflowError
15:32jgrantat clojure.lang.Numbers$IntegerOps.equiv(Numbers.java:444)
15:33kotarakBecause the jvm has no tail call optimisation
15:33kotarakuse loop and recur for such things
15:33jgrantthat function does not use tail-recursion
15:34jgrantjust simple recursion
15:34kotarakjgrant: then it will even stack overflow on things like scheme
15:34jgrantno you are wrong about that
15:37kotarakjgrant: no I am not. The nice thing about tail recursion is that it runs in constant space (with TCO), recursion as in your example does not since the original context has to be saved.
15:38jgrantrecursion in lisp or dialects is idiomatic and fundamental
15:38jgrantit's one of the things that make lisp well.... ...lisp
15:38kotarakyes and every decent text will tell you: use tail recursion.
15:39jgrantreally ? which ones ?
15:39jgranttail recursion is simply an optional compiler optimization
15:39kotarakeg. "teach yourself scheme in fixnum days", IIRC
15:39jgrantit's not required by any implementation
15:40kotarakin scheme it is part of the RxRS
15:41jgrantthe code above runs perfectly on mzscheme, scheme48 and a couple others
15:41mac__kotarak is right, you can't get optimization unless you have the recursive call in a place that the compiler recognizes as tail position, even in other lisps. If you do a non tail recursion that is large enough you will blow the stack. Nothing strange about that, just has different limits (depth) in different languages and runtimes
15:41jgrantalso with slight modification on sbcl, allegro, clozure(ccl) and lispworks
15:42jgrantkotarak has changed my initial question
15:42jgranti'm not asking about tail call optimization
15:42kotarakI did?
15:42jgrantsimply recursion
15:42mac__oh, then use loop/recur to get optimization, otherwise it will be nested calls
15:42kotarakYou asked, why your code does not work. And it doesn't work because it uses recursion.
15:43kotarakEven with tail recursion it wouldn't work, because the JVM does not support TCO.
15:43jgrantis it 'my' code that does not 'work' ?
15:44mac__but loop/recur in clojure "supports TCO" :) so use that?
15:44jgrantthat's merely and idiomatic factorial function
15:44jgrantfor ANY lisp dialect
15:44kotarakjgrant: sorry. It works. But it has a problem.
15:44jgrantlets try this from another angle...
15:44Chouserjgrant: your example will use 10000 stack frames in very nearly any language. Whether that's enough to cause an exception or not has to do with how deep the stack can get.
15:45mac__^^
15:45ChouserI believe there is a command-line option for java to request a bigger stack.
15:45jgrantChouser : no it will not
15:46jgrantthis is one if the reasons why people choose to use Lisp(or dialects) over stack based languages/vms
15:48Chouserlisp uses a stack. What little CL I know I learned from "on lisp", and it devotes several sections on how to restructure your code so that recursion happens in the tail position.
15:48kotarakSICP (or how it is called) will probably say the same.
15:49mac__yes and SICP is about scheme, not CL, so that goes for scheme too, at least their version
15:50kotarakTCO is a requirement in the RxRS, the Scheme standard.
15:51mac__which means it has a stack ;)
15:51jgrantkotarak, Chouser : you are confused about the use of the word 'stack' in 'On Lisp' and 'SICP'
15:51jgrantIn 'SICP' page 506 he's referring to the implementation of a stack for the register machine NOT a stack in the underlying implementation of Scheme
15:53jgrantAll of CH.5 in 'SICP' covers the design/implentation of a register machine using scheme
15:53mac__Seems like this discussion has derailed because no matter who is right, it will still blow the stack in clojure since it uses java calls and the jvm does not do TCO so you have to use loop/recur to not blow the stack on deep recursion.
15:54mac__It's even kinda nice actually since the compiler will tell you when recur is not in tail position so it always get's optimized.
15:54jgrantmac__ : by that logic ANY lisp/scheme implementation should have the same problem because it's implemented in C/C++
15:54jgrantmac__ : but somehow it does not ;-)
15:56jgrantso it's hard to call clojure a dialect of lisp (even a lisp-1) if simple recursion is not supported
15:56mac__I was trying to answer you question which was why you couldnt do recursion that way safely in clojure right? The answer is that the jvm uses a stack and you are using too many stack frames with that function and therefore you need to use loop/recur instead or make the stack limit higher. There is no other way that I know of in clojure
15:57jgrantmac__ : this has less to do with the JVM but the actual implementation of clojure
15:58mac__well yes, but that's part of my point, since clojure uses javas call mechanism it is this way
15:59jgrantmac__ : right and if it does then you have hit it on the head as to why that's the problem
16:00jgrantmac__ : and why clojure is not a dialect of lisp at all (but does has some lisp features in syntax, macros)
16:00mac__Well, I'm not good enough at all this to answer why rich did it that way, you need to ask him. I think I've seen a discussion about this on the google group, start by searching there
16:00jgrantmac__ : I would love to hear Rich's response on this, could you point me to it somewhere ?
16:00kotarakI think it was something about Java interaction.
16:00Chouserit doesn't blow the JVM operator stack (which is used instead of registers), it blows the JVM's call stack, which all these languages use.
16:01mac__here is the group, don't recall the discussion topic though, use the search field
16:01mac__http://groups.google.com/group/clojure
16:02jgrantThanks
16:03jgrantSo according to Rich Clojure will never be a lisp dialect but simply some type of functional language
16:03jgrantClojure could have been implemented with a heap-based stack, with a
16:03jgrantcost in performance and call-compatibility with Java. I chose not to
16:03jgrantdo so, and am very happy with the results. It's not an aspect of
16:03jgrantClojure that is going to change.
16:03jgrantSorry the last 5 lines are a quote
16:05jgrantand
16:05jgrantRIch : As such, it has its own set of idioms.
16:05mac__there you go, it's for performance and java interop, good reasons IMO, you get used to loop/recur pretty fast
16:06jgrantand that's fine I agree completely that not all functional languages will follow all of Lisps features BUT it's these features of Lisp that make it
16:06jgrantand Clojure should not be referred to as a Lisp by any stretch
16:07jgrantIt's definitely not a lisp-1
16:09jgrantThe very first paper by McCarthy in 1960 was titled "Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I"
16:10jgrantwhich detailed Lisp's design
16:13jgrantThe very first 2 implementations by Russell (in assembly language) supported recursion
16:13arohnerwhat does lisp-1 vs. lisp-2 have to do with recursion?
16:14mac__well if you absolutely insist that recursion must be done using the original name of the function then you can avoid stack blowage by using a lazy sequence in clojure, look up lazy-cons. I don't see you point at all.
16:14jgrantIt cannot even be done with (recur ...) in clojure , you are forced to implement it as tail-recursive
16:14mac__if you can write a function that looks like a recursive function but compiles to an iterative loop, why do you need to care?
16:14jgrantwhat about n-recursive functions ?
16:16jgrantSo fine Clojure is a functional language
16:16jgrantbut please do not keep calling it a Lisp (see the headline of this room above)
16:37shooverthat's an interesting definition of lisp. McCarthy's paper just says functions can call themselves, with no stated depth requirement. Norvig and Pitman say not to use recursion for iteration (http://www.cs.umd.edu/~nau/cmsc421/norvig-lisp-style.pdf). And a simple emacs lisp function just blew up at a depth of 347.
16:38kotarakSince the state of the function has to be saved, it doesn't matter whether you have a stack or not. At some point in time you will run out of space. With a tail call and TCO the function runs in constants space. So this cannot happen.
16:38shooverAh, that too
16:40mac__yeah, jgrant was weird. I always thought what made lisp lisp is the combination of read/eval and sexp/macros
16:40mac__that's pretty much the only thing still unique to lisp
16:41kotarakI actually don't care. Lisp is Lisp. Clojure is Clojure. Scheme is Scheme. And at least the latter two are fun. :)
16:42mac__yeah I don't understand why he made a big deal about it
16:44shooverThis all speaks to the accuracy of Clojure's tagline. Please don't change it
17:19albinoIs someone here writingcode.blogspot.com ?
17:47Chouserwell it's a little unfair to challenge jgrant's statements while he's not here, but I don't want to leave them unchallenged.
17:48ChouserIf I understood him correctly, the following Common Lisp function when called will run forever but not crash: (defun i () (+ 1 (i)))
17:48kotarakThat was his claim.
17:48ChouserExecuting that in Steel Bank Common Lisp, I get "Control stack exhausted (no more space for function call frames). This is probably due to heavily nested or infinitely recursive function calls."
17:49kotarakSurprise.
17:50ChouserSimilarly in clojure, (defn i [] (+ 1 (i))) produces java.lang.StackOverflowError
17:50kotarakIt doesn't matter whether there is a stack involved or not. The machine has only finite memory to save function contexts.
17:50Chouser(when I run (i))
17:50kotarakThere was some explanation like this:
17:51kotarak(fac n)
17:51kotarak(* n (fac (- n 1)))
17:51ChouserIf I put the lisp recursion in tail position, like this (defun i () (i)) then indeed SPCL seems to run indefinitely without crashing.
17:51kotarak(* n (* n-1 (fac (- n-1 1)))
17:51kotarak---> grows into that direction
17:51Chouserkotarak: yup
17:51kotarak(fac n 1)
17:52kotarak(fac n-1 n)
17:52kotarak(fac n-2 n*n-1)
17:52ChouserThe equivalent clojure also runs indefinitely without crashing: (defn i [] (recur))
17:52kotarakstays constant
17:54kotarakI think he got something terribly wrong. And it shows that prove-by-experiment doesn't really work.
17:56scgilardialthough disprove by experiment works fine. a "simple" recursive factorial in DrScheme with a memory limit of 128MB runs out of memory at some value under a million.
17:58kotarak"prove" by counter-example, yes. But he was some kind of advice-resistent.
17:59arbschtproof by experiment doesn't always work, then. it does really work sometimes, though
18:01arbschtand that was the most puzzling definition of lisp I've encountered
18:18rhickeysorry I missed jgrant, here are the facts:
18:19rhickeyLisp-1 has nothing to do with TCO, it has to do with whether functions have an independent namespace. Clojure is like Scheme in that they don't, so both are Lisp-1s.
18:19rhickeySupporting recursion has nothing to do with TCO. All Lisps support recursion (a function calling itself), and so does Clojure
18:20rhickeyScheme requires TCO, Common Lisp does not. Common Lisps are obviously Lisps, and so is Clojure
18:20rhickeyClojure is not a Scheme
18:24Chouserrhickey: we're all sorry you missed jgrant :-)
19:46abrooksjgrant: There was some reply to your Clojure as Lisp inquiry: http://clojure-log.n01se.net/date/2008-07-26.html
19:46abrooksjgrant: You'd probably be best scrolling down to the bottom.
22:27jgrantabrooks : thanks I see rich's response
22:28jgrantnot sure why this became a discussion about TCO
22:28jgrantmy initial question had to do with simple recursion
22:29jgrantand rich's response that i quoted earlier today already provided the answer -->
22:30jgranthttp://groups.google.com/group/clojure/browse_thread/thread/72a7fa0fe5a56c9c/e3849c42b21551c0?lnk=gst&q=recursion#e3849c42b21551c0
22:30jgrant"Clojure could have been implemented with a heap-based stack, with a"
22:30jgrantcost in performance and call-compatibility with Java. I chose not to
22:30jgrantdo so, and am very happy with the results. It's not an aspect of
22:30jgrantClojure that is going to change. "
22:31jgrantit was a design choice to not allow recursion until until the heap allocated memory is exhausted
22:31jgrantand that's fine
22:32jgrantAs I've stated here and elsewhere I think Clojure is great, it's probably my most favorite language on the JVM
22:32jgrantthanks again Rich
22:38jgrantAs to my personal opinion about why it's not really a Lisp...
22:38jgrant...from McCarthy's original paper in 1960 :
22:39jgrant(in the introduction)
22:39jgranthttp://www-formal.stanford.edu/jmc/recursive/node1.html
22:40jgrantIt's clearly stated what Lisp was intended to be :
22:40jgrant"In this article, we first describe a formalism for defining functions recursively."
22:41jgrantonly after that came s-expressions and s-functions and thirdly an example of the s-function 'apply'
22:42jgrantThe paper itself is titled "Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I"
22:42jgrantThis is just my opinion as calling Clojure a dialect of Lisp
22:45jgranthowever it's definitely a functional language
23:27dudleyfjgrant: Are you claiming that Clojure doesn't support "defining functions recursively"?
23:27ChouserIf you exclude TCO from the conversation, Clojure supports recursion just as well as Common Lisp does, as my SBCL exmples help demonstarte.
23:31Chouserdudleyf's question is better than my assertion. Let's go with that. :-)