#clojure log - Jul 26 2008

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

1:55 jykrd: hi

1:56 I'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

1:56 (runs system commands)

1:57 And to go off of, I'm trying to glean the method from the gui example on the wiki

1:58 so the first thing I did was converted this: Process p = Runtime.getRuntime().exec("ps -ef");

1:58 to this: #^Process p (. (. (Runtime getRuntime) exec (str "ps -ef")))

1:59 (inside a let)

1:59 But I get the feeling that's not the correct way

2:00 I'm not worried about the str so much.. more so the #^Process at the beginning

2:05 mebaran151: I think you can drop that

2:05 clojure does a little bit of type inference

2:06 jykrd: so does Runtime.getRuntime() always return a Process? I was figuring that line was doing type casting, or casting to the super, or something

2:06 Would have expected to see Runtime p = Runtime.getRuntime()

2:07 mebaran151: I'm not super familiar with that call

2:07 jykrd: ok

2:07 mebaran151: but yeah, I suppose if the javadocs say so it must be true

2:07 jykrd: well, from the repl, that compiles, so I guess I'll keep trucking

2:08 mebaran151: I think it just takes those comments as hints though

2:08 so even if you were wrong, it would valiantly try

2:08 jykrd: now, to do this in a let : BufferedReader stdInput = new BufferedReader(new

2:08 InputStreamReader(p.getInputStream()));

2:08 mebaran151: I hate how long java names are

2:09 jykrd: would is there a more graceful way than: stdinput (new BufferedReader (new InputStreamReader (. p getInputStream)))

2:10 mebaran151: not in java land

2:10 jykrd: ok.. Well that might work then

2:10 mebaran151: but I don't think it would be much more graceful in java anway

2:10 jykrd: well, I mean, in clojure, is there a better way than calling a new withing a new

2:13 mebaran151: you can use doto for a lot of this

2:13 oh yeah

2:13 ClassName.. make work

2:13 I think I saw that in the docs

2:13 it's a macro that automagically instantiates that class

2:14 jykrd: huh

2:14 it works

2:18 You 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

2:22 mebaran151: yeah I'm using it for a cool webstartup that's partially written in scala

2:22 it would be really nice if the docs weren't so non-existent

2:23 or at least if they could wiki the doc section so we could add comments

2:23 you wouldn't use a while loop in clojure thouhg: it's not very functional

2:23 what are you trying to do

2:23 usually map or reduce will get you 90 percent there....

2:24 jykrd: trying to do:

2:24 while ((s = stdInput.readLine()) != null) {

2:24 System.out.println(s);

2:24 }

2:25 mebaran151: reading a file eh

2:26 I've never really understood how do that functionally but we could write a monster hybrid for kicks

2:26 jykrd: And I'm actually thinking: (loop [s (. stdInput readLine)]

2:26 (when-not (= s nill)

2:26 (.. System out (println (str s)))))

2:26 std input

2:26 mebaran151: I think loop is only for recur

2:27 jykrd: oh yea, and I'd have to add a recur at the end I guess

2:27 mebaran151: you could do something using

2:27 jykrd: with the same condition as when-not or something

2:27 mebaran151: (repeatedly (. stdInput (readline))

2:27 jykrd: hmm

2:27 mebaran151: that builds a lazy list of readlines

2:27 jykrd: really?

2:27 mebaran151: yeah

2:27 cloisng the file might be problematic though

2:28 if you close the file and try to run that

2:28 jykrd: its std input, not a file

2:28 mebaran151: some sort of exception has to be thrown

2:28 stdinput my bad

2:28 jykrd: you remember which doc page the repeatedly was on?

2:28 mebaran151: the api is all doc'ed alpabetically

2:28 do a search text in firefox for lazy

2:29 and you'll find a lot of cool macros rick wrote

2:30 jykrd: gah, it's all so terse

2:33 so, (repeatedly (.. System out (println (. stdInput (readline))))

2:33 or something?

2:39 gah.. looping control structures.. I'm having such a hard time wrapping my head around them in a functional way

2:40 mebaran151: yeah

2:40 io is not the best place to learn about fp

2:42 it would more like be something like

2:44 repeatedly (fn [] (.. System (println (.stdInput (readline))

2:50 jykrd: eeeoooh

2:56 mebaran151: you might put some more conditional logic in there

2:56 to represent each iteration

2:57 jykrd: yea, it's flooding the screen with nills

2:57 mebaran151: oh yeah

2:57 don't directly type in repeatedly

2:57 it will try to evaluate it fully

2:57 you have set it equal to something

2:57 like (def lines (repeatedly what .....))

2:57 then do first and rest stuff on it

2:57 jykrd: huh

2:58 hmm

2:58 mebaran151: to print something it has to evaulate it

2:58 prn recursive tries to print everything, which fails for an infinie list

3:00 just keep a little pointer around and iterate until nil

3:01 jykrd: oh my gosh, it almost works :)

3:01 hoeck: or use (take n (repeatedly ..))

3:04 jykrd: wow.. I've got output

3:05 I'm running the my linux' ps command from clojure ! :)

3:06 now 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

3:06 you guys kick ass.. thanks.. I need to sleep now, but I'm glad I stayed up :) night

3:07 mebaran151: np

3:07 just looking at line-seq

3:08 I think that clojure should have some more clojurey file openers

3:09 hoeck: mebaran151: what about "slurp"?

3:10 mebaran151: isn't that only for valid clojure files though

3:10 you know

3:10 better reading and writer

3:11 and maybe some more in depth control structures

3:11 *deserializing structures

3:11 boy am I tired

3:12 also I was workng with a colleague in clojure (which we've snuck in our project via the all knowing JVM)

3:12 we think that it would be relaly nice if you guys could open the clojure api to wiki comments

3:12 sort of like php

3:13 hoeck: aha, i don't know much about php

3:14 mebaran151: I don't either

3:14 but when I had to fix one script

3:14 it was really nice that the php docs had a comment section

3:14 and other users had recorded their thoughts

3:14 spruced with a little ajax, people could note whether or not to look at the comments

3:14 sometimes the function is sort of unclear how it works, esp with things like refs and agents

3:16 the 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

3:18 also 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

3:18 hoeck: yeah, the api docs are really huge and hard to search, especially if you don't know which function to search for

3:20 mebaran151: exactly

3:20 I'm currently writing a little object store in clojure sort of rucksack

3:20 hoeck: if you're on the repl, you can use (find-doc "file") to search for all functions containing "file" in their docstring

3:21 mebaran151: you have any suggestions, especially with regards to efficiently serializing a b* tree

3:22 hoeck: no, not really

3:22 mebaran151: it's hard to find good byte reading stuff on clojure

3:23 and I don't know much about training the interpreter to be more efficient at slurping in objects

3:24 hoeck: what kind of objects?

3:25 mebaran151: arbitrary hashes really

3:26 I do all the db management stuff using metadata which is really rather convenient

3:28 hoeck: i'm still wondering for what and when to use metadata, except for docstrings and test-related stuff

3:59 mebaran151: i guess rhickey is going to think about your suggestions when he is up again.

4:00 just found out that find-doc doesn't print the function name :(

4:00 mebaran151: I 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

4:00 when a call to save is made that is

4:00 I hope he does

4:01 I think clojure is a pretty cool language

4:01 that could use just a little bit more love

4:06 hoeck: aha, nice

4:07 what do you use for interfacing with the db?

4:22 mebaran151_: I'm gonna write that back end part later

4:22 write now

4:22 the filesystem is doing all the heavy lifting

4:24 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

4:27 hoeck: so you're using the clojure reader to read those vectors?

4:27 Laurent_: nickname lpetit

4:38 mebaran151_: hoeck: currently yes

4:39 I'm planning on supporting a sane way to query with simple key value semantics that can be joined together or orred

4:40 I've never found SQL very easy to grok myself

4:43 hoeck: mebaran151_: i learned sql by reading the documentation and source at work and by the help of my colleagues

4:43 mebaran151_: I know SQL, just it seems so inefficient to produce massive query strings

4:43 hoeck: but got really enlightened by the relational algebra

4:44 mebaran151_: and much of this data is free form, so it doesn't fit in the table metaphor very well

4:45 I know a bit of relation algebra actually. If SQL didn't seem so obsessed with covering up its relation roots

4:45 it might be more sane to code gen it

4:46 and I never thought it really stuck with lisp very well

4:50 anyway I'm going to bed

4:50 hoeck: but the relational algebra fits good into the lisp world, imho

4:50 mebaran151_: it does

4:50 I'll agree with that

4:50 however, far too many problems get solved with SQL aren't really relational in nature

4:51 hoeck: a algebra->sql compiler is on my todo list :)

4:51 mebaran151_: and SQL doesn't do its roots justice I don't think

4:51 it seems as though all the latest database tech is leaving the relational word

4:51 with products like s3 and clouddb and the whole google appdb

4:52 hoeck: yeah, i've heard of that

4:52 mebaran151_: it seems as though relational logic should be done in the language itself

4:52 with conj and disjuct operators on sets

4:52 hoeck: they are more like big berkeley-dbs

4:53 mebaran151_: we're planning on using S3 for some stuff in our app, so it seemed logical to role our own simple query engine

4:53 hoeck: i'm only working on a small-scale client-server insurance management application

4:54 mebaran151_: we're not so big yet ourselves

4:54 hoeck: (at work) so sql really fits that model

4:54 aha

4:54 mebaran151_: sql is a good fit if all your data is going to look the same

4:54 hoeck: but i guess its hard to roll your own query engine efficiently

4:55 mebaran151_: reading up on redblack trees

4:55 which I half way remember how to implement

4:55 there isn't too much magic to SQL systems, esp for single transactions

4:56 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)

4:57 it's handling insertion and deletion properly that normally gets ya, but I think Clojure actually provides some pretty powerful primitives along those lines

4:57 *leverage an index

4:59 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

5:00 hoeck: sometimes i'm really surprised how fast a crappy multiline sqlstatement on a long grown database schema can be

5:01 mebaran151_: yeah

5:01 is there anything good in clojure world for sql mapping

5:01 hoeck: okay, for short queries, i guess its the index which is responsible for the speed

5:01 mebaran151_: cl lisp had rucksack and I looked at elephant, but didn't find much for clojure

5:02 hoeck: spring,hibernate :)

5:02 mebaran151_: 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

5:03 wouldn't hibernate fail though because clojure hashes aren't really classes?

5:03 hoeck: iirc, there was a simple jdbc->clojure thing on the mailinglist

5:03 mebaran151_: seems like hibernate would have to be very Java or at least class oo centric

5:04 hoeck: i just know hibernate as a buzzword

5:05 mebaran151_: I've used it a little bit

5:05 it's pretty pretty fancy

5:07 hoeck: i never used java before, clojure was my first encounter with java

5:08 but 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

5:08 so clojure +1!

5:10 mebaran151_: I moved from Scala to Clojure

5:10 sometimes I mis the static types

5:11 hoeck: do you miss them for the speed you gain from static typing?

5:12 msingh: are places first class in clojure?

5:13 mebaran151_: hoeck: not for the speed, but for the way it guided my modeling

5:13 I have to be much more disciplined as I write lisp

5:13 kotarak: msingh: ehem... What is a place?

5:13 mebaran151_: I think clojure does a halfway decent job of coercing types

5:14 msingh: kotarak: not sure :)

5:14 mebaran151_: 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

5:15 something about static typing makes me feel warm and fuzzy

5:16 msingh: yes, that's how a straight jacket feels like

5:16 mebaran151_: well it does catch some quick bugs and makes sure that your functions interop properly

5:17 msingh: not an issue

5:17 kotarak: there is a nice example, where static type checking (with inferencing) caught a infinite loop.

5:17 msingh: in 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

5:18 mebaran151_: but for a current project, I want to be able to easily turn some of my functions into xml

5:18 lisp is really really really good for that

5:18 kotarak: type are another layer to transport information.

5:18 hoeck: i like the way common-lisp provides types, for having speed where its necessary

5:18 mebaran151_: the JVM mostly discards your type info

5:19 most of what I read doesn't really put too much emphasis on types

5:19 hoeck: yeah, on java, speed isn't such a big issue

5:19 aha

5:19 mebaran151_: most of them can be inferred by a smart compiler (aka Hotspot) and fairly efficiently statically inlined

5:23 hoeck: i wrote a little physics simulation in clojure, and it was as slow as hell :(

5:23 compared to the c++ demo in ran in wine

5:23 mebaran151_: hotspot does take awhile to warm up though

5:24 and I don't know much about how well it vectorizes code

5:24 hoeck: but it was fully dynamic, like adding objects at any time

5:25 well, it used the boxing number types in clojure, and vector-tuples, so it wasn't trimmed on speed either

5:25 and it was way more fun than writing a c++ app :)

5:26 mebaran151_: can you tell clojure to downcast if to unboxed primitives if you know best?

5:27 hoeck: there are some tweaks on unboxed array access, and on using unboxed numbers

5:29 it was discussed in a group-thread about imagej

5:54 mebaran151_: I need to get myself on the list...

5:56 hoeck: clojure moves pretty fast, personally, i read the list and the clojure-log

6:05 mebaran151_: because otherwise, I don't see any reason why clojure objects should technically have any slower dispatch once compiled

6:05 but I'm gonna take a na

6:05 p

6:06 good night all

11:47 jykrd1: yerrp

11:56 I'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:56 but there's no /newlines in the output

11:57 it's just one long string.

11:57 doesn't ps print a string formated with new lines?

11:57 kotarak: What you just pasted is a list of strings, each string representing one line.

11:57 jykrd1: and tabs

11:57 rhickey: that looks like a list of strings

11:57 jykrd1: oh

11:58 so, lines (repeatedly (fn [] (. stdInput readLine))) is creating a list of words, rather than lines, really

11:59 er, (let [lines (repeatedly.... etc

11:59 rhickey: no, it's creating a list of lines, each of which is a string

11:59 kotarak: I would expect it to produce, what you pasted: a list of lines

12:01 rhickey: readLine doesn't return the line terminators

12:01 jykrd1: right... so should I concatenate a /nl onto lines each line after it returns?

12:01 rhickey: depends on your goal - what is your goal?

12:02 jykrd1: to make a function that can take any shell command and return it like it would in the shell, i guess

12:03 rhickey: return a single string or print it?

12:03 print directly: (dorun (map println ["a" "b" "c"]))

12:04 print into a string: (with-out-str (dorun (map println ["a" "b" "c"])))

12:04 replace ["a" "b" "c"] with your list of lines

12:44 albino: jykrd: fyi, I think the java sigar libs have ps in them if you wanted to call an api instead of forking a process

13:03 jykrd: albino: 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:03 seems to work

13:04 kotarak: Heretic, I know, but: there is also scsh which is kind of specialised on shell scripting, in case you just want something lispish.

13:05 albino: jykrd: 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:17 shoover: albino: 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:20 albino: shoover: getting stuff done on unix requires calling all sorts of command line utilities

13:20 shoover: for work I write a lot of code that automates the use of our products via command line

13:20 shoover: In my case it ends up being calls to subprocess.Popen in python

13:24 shoover: albino: 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:27 albino: shoover: yep, no api like the command line :)

13:42 mebaran151: I'm gonna reiterate my proposal for wiki'izing the docs

13:42 rhickey: there is a wiki, the docs are a reference

13:43 mebaran151: it would be nice if they weren't just a long alphabetical list

13:43 rhickey: there are many pages of docs in addition to the API list

13:44 mebaran151: and I think certain functions could stand nice little docs

13:44 *comments

13:45 kind of the way php lets users add optional annotations and tips

13:45 rhickey: link?

13:51 mebaran151: hello? do you have a link for the php wiki you are recommending I emulate?

13:51 mebaran151: oh sorry

13:52 I have to refind it: I haven't done php in quite awhile but I remember the comment system being superb

13:54 http://www.php.net/manual/en/install.macosx.bundled.php

13:54 look at the user contributed notes section

13:54 arohner: postgres has something similar

13:54 http://www.postgresql.org/docs/

13:54 mebaran151: postgres I think took the idea from the PHP people

13:55 arohner: the API section on the website is generated from the docstrings in the code, right?

13:55 so it's simple enough to patch that

13:56 mebaran151: we 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:56 rhickey: the 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:57 I understand the docs are not much of a tutorial

13:58 mebaran151: I was pretty new to LISP, but luckily alot of the scheme stuff on the internet helps out

13:58 rhickey: but there needs to be an accurate reference somewhere

13:59 I've also put up many hours of talks on blip.tv

14:01 mebaran151: I'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:01 you can't just search text or skim a talk

14:56 jykrd: I'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:30 jgrant: is clojure a lisp-1 dialect ?

15:31 kotarak: I think so.

15:31 jgrant: http://clojure.org/lisps has more info on this.

15:32 jgrant: Really then why is this a problem ? -->

15:32 Clojure

15:32 user=> (defn fact[n]

15:32 (if (= n 0)

15:32 1

15:32 (* n (fact (- n 1)))))

15:32 #'user/fact

15:32 user=> (fact 10000)

15:32 java.lang.StackOverflowError

15:32 java.lang.StackOverflowError

15:32 at clojure.lang.Numbers$IntegerOps.equiv(Numbers.java:444)

15:33 kotarak: Because the jvm has no tail call optimisation

15:33 use loop and recur for such things

15:33 jgrant: that function does not use tail-recursion

15:34 just simple recursion

15:34 kotarak: jgrant: then it will even stack overflow on things like scheme

15:34 jgrant: no you are wrong about that

15:37 kotarak: jgrant: 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:38 jgrant: recursion in lisp or dialects is idiomatic and fundamental

15:38 it's one of the things that make lisp well.... ...lisp

15:38 kotarak: yes and every decent text will tell you: use tail recursion.

15:39 jgrant: really ? which ones ?

15:39 tail recursion is simply an optional compiler optimization

15:39 kotarak: eg. "teach yourself scheme in fixnum days", IIRC

15:39 jgrant: it's not required by any implementation

15:40 kotarak: in scheme it is part of the RxRS

15:41 jgrant: the code above runs perfectly on mzscheme, scheme48 and a couple others

15:41 mac__: 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:41 jgrant: also with slight modification on sbcl, allegro, clozure(ccl) and lispworks

15:42 kotarak has changed my initial question

15:42 i'm not asking about tail call optimization

15:42 kotarak: I did?

15:42 jgrant: simply recursion

15:42 mac__: oh, then use loop/recur to get optimization, otherwise it will be nested calls

15:42 kotarak: You asked, why your code does not work. And it doesn't work because it uses recursion.

15:43 Even with tail recursion it wouldn't work, because the JVM does not support TCO.

15:43 jgrant: is it 'my' code that does not 'work' ?

15:44 mac__: but loop/recur in clojure "supports TCO" :) so use that?

15:44 jgrant: that's merely and idiomatic factorial function

15:44 for ANY lisp dialect

15:44 kotarak: jgrant: sorry. It works. But it has a problem.

15:44 jgrant: lets try this from another angle...

15:44 Chouser: jgrant: 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:45 mac__: ^^

15:45 Chouser: I believe there is a command-line option for java to request a bigger stack.

15:45 jgrant: Chouser : no it will not

15:46 this is one if the reasons why people choose to use Lisp(or dialects) over stack based languages/vms

15:48 Chouser: lisp 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:48 kotarak: SICP (or how it is called) will probably say the same.

15:49 mac__: yes and SICP is about scheme, not CL, so that goes for scheme too, at least their version

15:50 kotarak: TCO is a requirement in the RxRS, the Scheme standard.

15:51 mac__: which means it has a stack ;)

15:51 jgrant: kotarak, Chouser : you are confused about the use of the word 'stack' in 'On Lisp' and 'SICP'

15:51 In '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:53 All of CH.5 in 'SICP' covers the design/implentation of a register machine using scheme

15:53 mac__: 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:54 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:54 jgrant: mac__ : by that logic ANY lisp/scheme implementation should have the same problem because it's implemented in C/C++

15:54 mac__ : but somehow it does not ;-)

15:56 so it's hard to call clojure a dialect of lisp (even a lisp-1) if simple recursion is not supported

15:56 mac__: 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:57 jgrant: mac__ : this has less to do with the JVM but the actual implementation of clojure

15:58 mac__: well yes, but that's part of my point, since clojure uses javas call mechanism it is this way

15:59 jgrant: mac__ : right and if it does then you have hit it on the head as to why that's the problem

16:00 mac__ : and why clojure is not a dialect of lisp at all (but does has some lisp features in syntax, macros)

16:00 mac__: 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:00 jgrant: mac__ : I would love to hear Rich's response on this, could you point me to it somewhere ?

16:00 kotarak: I think it was something about Java interaction.

16:00 Chouser: it 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:01 mac__: here is the group, don't recall the discussion topic though, use the search field

16:01 http://groups.google.com/group/clojure

16:02 jgrant: Thanks

16:03 So according to Rich Clojure will never be a lisp dialect but simply some type of functional language

16:03 Clojure could have been implemented with a heap-based stack, with a

16:03 cost in performance and call-compatibility with Java. I chose not to

16:03 do so, and am very happy with the results. It's not an aspect of

16:03 Clojure that is going to change.

16:03 Sorry the last 5 lines are a quote

16:05 and

16:05 RIch : As such, it has its own set of idioms.

16:05 mac__: there you go, it's for performance and java interop, good reasons IMO, you get used to loop/recur pretty fast

16:06 jgrant: and 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:06 and Clojure should not be referred to as a Lisp by any stretch

16:07 It's definitely not a lisp-1

16:09 The very first paper by McCarthy in 1960 was titled "Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I"

16:10 which detailed Lisp's design

16:13 The very first 2 implementations by Russell (in assembly language) supported recursion

16:13 arohner: what does lisp-1 vs. lisp-2 have to do with recursion?

16:14 mac__: 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:14 jgrant: It cannot even be done with (recur ...) in clojure , you are forced to implement it as tail-recursive

16:14 mac__: 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:14 jgrant: what about n-recursive functions ?

16:16 So fine Clojure is a functional language

16:16 but please do not keep calling it a Lisp (see the headline of this room above)

16:37 shoover: that'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:38 kotarak: Since 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:38 shoover: Ah, that too

16:40 mac__: yeah, jgrant was weird. I always thought what made lisp lisp is the combination of read/eval and sexp/macros

16:40 that's pretty much the only thing still unique to lisp

16:41 kotarak: I actually don't care. Lisp is Lisp. Clojure is Clojure. Scheme is Scheme. And at least the latter two are fun. :)

16:42 mac__: yeah I don't understand why he made a big deal about it

16:44 shoover: This all speaks to the accuracy of Clojure's tagline. Please don't change it

17:19 albino: Is someone here writingcode.blogspot.com ?

17:47 Chouser: well 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:48 If I understood him correctly, the following Common Lisp function when called will run forever but not crash: (defun i () (+ 1 (i)))

17:48 kotarak: That was his claim.

17:48 Chouser: Executing 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:49 kotarak: Surprise.

17:50 Chouser: Similarly in clojure, (defn i [] (+ 1 (i))) produces java.lang.StackOverflowError

17:50 kotarak: It doesn't matter whether there is a stack involved or not. The machine has only finite memory to save function contexts.

17:50 Chouser: (when I run (i))

17:50 kotarak: There was some explanation like this:

17:51 (fac n)

17:51 (* n (fac (- n 1)))

17:51 Chouser: If I put the lisp recursion in tail position, like this (defun i () (i)) then indeed SPCL seems to run indefinitely without crashing.

17:51 kotarak: (* n (* n-1 (fac (- n-1 1)))

17:51 ---> grows into that direction

17:51 Chouser: kotarak: yup

17:51 kotarak: (fac n 1)

17:52 (fac n-1 n)

17:52 (fac n-2 n*n-1)

17:52 Chouser: The equivalent clojure also runs indefinitely without crashing: (defn i [] (recur))

17:52 kotarak: stays constant

17:54 I think he got something terribly wrong. And it shows that prove-by-experiment doesn't really work.

17:56 scgilardi: although 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:58 kotarak: "prove" by counter-example, yes. But he was some kind of advice-resistent.

17:59 arbscht: proof by experiment doesn't always work, then. it does really work sometimes, though

18:01 and that was the most puzzling definition of lisp I've encountered

18:18 rhickey: sorry I missed jgrant, here are the facts:

18:19 Lisp-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:19 Supporting recursion has nothing to do with TCO. All Lisps support recursion (a function calling itself), and so does Clojure

18:20 Scheme requires TCO, Common Lisp does not. Common Lisps are obviously Lisps, and so is Clojure

18:20 Clojure is not a Scheme

18:24 Chouser: rhickey: we're all sorry you missed jgrant :-)

19:46 abrooks: jgrant: There was some reply to your Clojure as Lisp inquiry: http://clojure-log.n01se.net/date/2008-07-26.html

19:46 jgrant: You'd probably be best scrolling down to the bottom.

22:27 jgrant: abrooks : thanks I see rich's response

22:28 not sure why this became a discussion about TCO

22:28 my initial question had to do with simple recursion

22:29 and rich's response that i quoted earlier today already provided the answer -->

22:30 http://groups.google.com/group/clojure/browse_thread/thread/72a7fa0fe5a56c9c/e3849c42b21551c0?lnk=gst&q=recursion#e3849c42b21551c0

22:30 "Clojure could have been implemented with a heap-based stack, with a"

22:30 cost in performance and call-compatibility with Java. I chose not to

22:30 do so, and am very happy with the results. It's not an aspect of

22:30 Clojure that is going to change. "

22:31 it was a design choice to not allow recursion until until the heap allocated memory is exhausted

22:31 and that's fine

22:32 As I've stated here and elsewhere I think Clojure is great, it's probably my most favorite language on the JVM

22:32 thanks again Rich

22:38 As to my personal opinion about why it's not really a Lisp...

22:38 ...from McCarthy's original paper in 1960 :

22:39 (in the introduction)

22:39 http://www-formal.stanford.edu/jmc/recursive/node1.html

22:40 It's clearly stated what Lisp was intended to be :

22:40 "In this article, we first describe a formalism for defining functions recursively."

22:41 only after that came s-expressions and s-functions and thirdly an example of the s-function 'apply'

22:42 The paper itself is titled "Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I"

22:42 This is just my opinion as calling Clojure a dialect of Lisp

22:45 however it's definitely a functional language

23:27 dudleyf: jgrant: Are you claiming that Clojure doesn't support "defining functions recursively"?

23:27 Chouser: If you exclude TCO from the conversation, Clojure supports recursion just as well as Common Lisp does, as my SBCL exmples help demonstarte.

23:31 dudleyf's question is better than my assertion. Let's go with that. :-)

Logging service provided by n01se.net