Live data from Hacker News

Racket – Lisp beyond Clojure

slides.com

101–110 of 179 posts

Re: Racket – Lisp beyond Clojure

#101

Earlier quoted context omitted.

I guess I don't understand what the big deal is with tail call optimization. Could someone give an example where it really shines and clojure's loop/recur just doesn't? If you are looking to put time into a programming language that is interesting in and of itself, I'd suggest Haskell.

Looping is fine for imperative languages. It should be the norm for performance sensitive things since that is how the CPU works. It is just easier than trying to make a smart compiler turn your recursion into looping constructions. However, for functional languages you really want TCO to work properly so you can write your algorithms in a properly functional way. And you don't just want self-calls to work, but full…

I will have to look for mutual recursion support (or lack thereof) in clojure.

Clojure's loop/recur is a work-around for some issue with the JVM and lack of fine grained control over the stack. That said, It's not a simple loop, the keyword "loop" is effectively an anonymous function that gets called by the "recur" keyword, with parameters.

An example:

  (loop [iter 1
       acc  0]
  (if (> iter 10)
    (println acc)
    (recur (inc iter) (+ acc iter))))
I don't know if that is any different than other lisps or not. In case it's less less than clear, the bracketed portion after the "loop" keyword is an initial binding form (setting iter to 1, and acc to 0), and thereafter iter and acc are just considered parameters.

For self recursion, that seems like a fair compromise. No help at all for mutual recursion though.

Re: Racket – Lisp beyond Clojure

#102

I'd think Common Lisp is the Lisp beyond Clojure. Also, I just see slides that have (googleable) terms, is there a recording of this presentation? EDIT: see mkozlows' comment (THANKS!!!)

I tried to get more into CL because of implementations like SBCL and because it's standardized, but modularization/package management turned out to be too verbose and archaic for my taste. In Racket, by default a file creates a module, I import things, export stuff and done. That's really very handy, because I hate fiddling around with package declarations and paths -- these are a pain in the ass in almost every olde…

If you like racket modules, you should look at package-inferred-system in ASDF. Not quite as little boilerplate, but close.

Re: Racket – Lisp beyond Clojure

#103
post #97

Earlier quoted context omitted.

I guess I don't understand what the big deal is with tail call optimization. Could someone give an example where it really shines and clojure's loop/recur just doesn't? If you are looking to put time into a programming language that is interesting in and of itself, I'd suggest Haskell.

loop/recur is good for replacing structured loops but tail recursion is more general, since it can replace arbitrary gotos. One example is given by Guy Steele in "Why Object-Oriented Languages need Tail Calls". Basically, tail recursion lets you keep O(1) stack space even in the face of opaque method dispatching in OO code. https://eighty-twenty.org/2011/10/01/oo-tail-calls Another required reading are the "Lambda th…

Thanks! These must be where the website/blog got its name. I actually thought that was what you were referring to at first.

Re: Racket – Lisp beyond Clojure

#104
post #84

Unhappy with the current state of functional programming. I know I should't be. I have a lot of options. I went to school at UC Berkeley. My first language was Scheme. Then Elisp. CLOS was in the first few too. I really didn't learn C or C++ until second semester. A few months ago I had to pick up enough Scala to figure out what some code did in a project and I wasn't really happy with the language. I realize it is m…

Haskell and OCaml are both great. I've had a fair amount of experience with both of them as well as Racket and, while I rather liked Racket, I would definitely order them Haskell > OCaml > Racket. (I did 61A in Scheme too, coincidentally.) I'm using Haskell professionally now and, while there are still a few things I miss from Racket and even OCaml, Haskell delivers the best overall programming experience I've encoun…

Also started with 61a in Scheme. How would you compare Scheme to Racket?

Re: Racket – Lisp beyond Clojure

#105

Unhappy with the current state of functional programming. I know I should't be. I have a lot of options. I went to school at UC Berkeley. My first language was Scheme. Then Elisp. CLOS was in the first few too. I really didn't learn C or C++ until second semester. A few months ago I had to pick up enough Scala to figure out what some code did in a project and I wasn't really happy with the language. I realize it is m…

I guess I don't understand what the big deal is with tail call optimization. Could someone give an example where it really shines and clojure's loop/recur just doesn't? If you are looking to put time into a programming language that is interesting in and of itself, I'd suggest Haskell.

It's a big deal since it's not really about optimization, but more about the overall coding style and thought process.

With TCO, you start seeing functions as composable code blocks rather than something that is called and then return from. State machines are just mutually tail-calling functions---it's not that state machines are written so, but that in your mental model two are the same. And usually a program is humongous multi-layered state machine.

Suppose you want to abstract the part of the loop. You just write a generic version that tail-calls user-passed function. Users can extend the loop freely, even interlacing two independent loops by mutually calling them (which can't be done with callback model without consuming stack frames).

It's really a matter of style, but for those who get used to think in this way, not having guaranteed TCO is like writing code with one hand tied up in the back.

Re: Racket – Lisp beyond Clojure

#106

Unhappy with the current state of functional programming. I know I should't be. I have a lot of options. I went to school at UC Berkeley. My first language was Scheme. Then Elisp. CLOS was in the first few too. I really didn't learn C or C++ until second semester. A few months ago I had to pick up enough Scala to figure out what some code did in a project and I wasn't really happy with the language. I realize it is m…

I guess I don't understand what the big deal is with tail call optimization. Could someone give an example where it really shines and clojure's loop/recur just doesn't? If you are looking to put time into a programming language that is interesting in and of itself, I'd suggest Haskell.

An interesting thing about general tail recursion is that it's composable.

Closure's loop/recur is a special case implementation of a common pattern. That's Ok, but it can't extend.

Any higher order function in scheme can be parameterized with methods that should be tail recursive. No special language support needed. That's why for-each is a procedure instead of a special form in scheme.

This allows libraries (like SFRI-1) or DSLs to be created that expect callers can conform by contract instead of by using special forms. Callers, in turn, can create abstractions over the libraries and DSLs that are equally general, instead of being strongly influenced by what they're built on.

Clojure does a really nice job of creating reusable abstractions. From what I understand, tail-call optimization isn't possible in the JVM, so we have iterators and lazy evaluation first-class instead; which has other nice advantages for creating abstractions.

Re: Racket – Lisp beyond Clojure

#107

Earlier quoted context omitted.

You are forgetting about the function prologue, epilogue, and the maintenance of the various pointers. It certainly isn't as simple as a jump as you imply. To do proper TCO most implementation resort to function trampolines and other self-modifying trickery to get similar to loop-like performance. Within the confines of the JVM, without doing extensive source analysis, I doubt there is even a way to do it.

this is outside my field of expertise. Can you give an example of a tail call that needs "trickery"? I'm not 100% on this, but when you have a tail call I don't think you have to remember the state of the stack frame. "function prologue, epilogue, and the maintenance of the various pointers" aren't god given rules - they're things dictated by something like the C ABI so you can resume the caller. So if you're thinkin…

When TCO is "lexically scoped" like loop/recur, the compiler can handle it.

When HoF are involved, you may have a case where a procedure calls a procedure-parameter, which calls another, and another... Something about the runtime has to recognize this or else the compiler has to accept more constrains.

See, for example, how Gambit-C implements tail calls by compiling modules to single C functions and how there is a trade off for procedure calls across module boundaries versus Chicken Scheme's approach to essentially garbage-collecting the call stack.

Re: Racket – Lisp beyond Clojure

#108

Unhappy with the current state of functional programming. I know I should't be. I have a lot of options. I went to school at UC Berkeley. My first language was Scheme. Then Elisp. CLOS was in the first few too. I really didn't learn C or C++ until second semester. A few months ago I had to pick up enough Scala to figure out what some code did in a project and I wasn't really happy with the language. I realize it is m…

Can you elaborate a little on what you think lacks in Clojure?

I ask because I've never been happier with any language (I came from Java/Peolog) and I rarely use loops (maybe one for every 2kloc, mostly because a reduce does it in most cases) so I don't know what else I might be missing without knowing it.

Re: Racket – Lisp beyond Clojure

#109

Earlier quoted context omitted.

Looping is fine for imperative languages. It should be the norm for performance sensitive things since that is how the CPU works. It is just easier than trying to make a smart compiler turn your recursion into looping constructions. However, for functional languages you really want TCO to work properly so you can write your algorithms in a properly functional way. And you don't just want self-calls to work, but full…

I will have to look for mutual recursion support (or lack thereof) in clojure. Clojure's loop/recur is a work-around for some issue with the JVM and lack of fine grained control over the stack. That said, It's not a simple loop, the keyword "loop" is effectively an anonymous function that gets called by the "recur" keyword, with parameters. An example: (loop [iter 1 acc 0] (if (> iter 10) (println acc) (recur (inc it…

I never had to use it but I recall there was a 'trampoline' fn for mutual recursion

Re: Racket – Lisp beyond Clojure

#110

Earlier quoted context omitted.

I will have to look for mutual recursion support (or lack thereof) in clojure. Clojure's loop/recur is a work-around for some issue with the JVM and lack of fine grained control over the stack. That said, It's not a simple loop, the keyword "loop" is effectively an anonymous function that gets called by the "recur" keyword, with parameters. An example: (loop [iter 1 acc 0] (if (> iter 10) (println acc) (recur (inc it…

I never had to use it but I recall there was a 'trampoline' fn for mutual recursion

Exactly. I once read a great article [1] written by Martin Trojer I think, it was about recursion in Clojure.

EDIT: [1] https://martintrojer.github.io/clojure/2011/11/20/tail-calls...

Post reply on HN