4 ms·
> Without TCO, you can't fully leverage functional composition and immutable data structures Look, I like tail calls as much as any language geek, but this sta
by brandonbloom 10y ago
> Without TCO, you can't fully leverage functional composition and immutable data structures
Look, I like tail calls as much as any language geek, but this statement is just plain silly. The idea that TCO is needed to "fully" leverage anything is silly. Never mind that necessitating so-called full leverage is pointless, as even supposedly partially leveraged anything can be useful. In the case of Clojure, function composition and immutable data structures are highly leveraged and, after learning the seq abstraction and lib functions, you won't even miss tail calls unless you try to write a direct-style interpreter for a language that supports recursion.
- willtim 10y agoPerhaps TCO is not required for idiomatic Clojure, but for advanced functional programming using e.g. Monads or CPS, TCO is absolutely necessary in practice.
- dragandj 10y agoClojure has TCO, though. This is what recur is for.
- willtim 10y agoNo Clojure does not have TCO, due to the JVM. It allows you to manually optimise self-recursion via recur. This is not enough for many advanced FP techniques, such as CPS. For example, using CPS and TCO, I can traverse a tree in constant stack space. I agree with the parent that lack of TCO in Clojure is probably not an issue for most.
- brandonbloom 10y agoThe fact that monads are not popular in Clojure is a good thing, IMHO. Besides, test.check and clojure.spec get by just fine with macros for generator monads. It's not quite perfect, and everyone would like proper tail calls, but it's far from an impediment for the overwhelming majority of tasks tackled with Clojure.
- willtim 10y agoI have already stated that it is quite possibly not a problem for Clojure, although this hasn't stopped all the downvotes I keep getting (which doesn't leave me with a good impression of Clojure users). My point is that, despite the claims of the parent post, TCO is needed for many advanced functional programming techniques.
- brandonbloom 10y agoYou're being down voted because you keep repeating a claim without evidence despite both evidence to the contrary and acknowledgement of the utility of tail calls.
- willtim 10y agoNo, I have been disputing the following parent claim: > The idea that TCO is needed to "fully" leverage anything is silly. I provided two examples, monads and CPS transforms, which require TCO to fully leverage in a strict language. But really any example where functions are dyamically composed as a pipeline needs TCO to avoid leaking stack. Your examples of a couple of test libraries in Clojure hardly constitute evidence that TCO is of limited utility.
- brandonbloom 10y ago> any example where functions are dyamically composed as a pipeline needs TCO to avoid leaking stack Sure, but in the rare case that this is a problem, you can trivially workaround it: (reduce (fn [acc f] (f acc)) init [f1 f2 f3]) This approach may not match the Haskell ideal of FP, but it's actually got many significant advantages. Frequently, programming with data structures is _better_ than programming with function composition. For example, you may choose to do something like this: (reduce (fn [acc f] (println "executing" f) (f acc)) init [#'f1 #'f2 #'f3]) Where this is now a pipeline with logging of the stages. You can't do that if you prematurely select function composition as your primary way to structure computations. The Haskell research community is in the process of undoing this brain damage on the monad front by embracing extensible effects, free(-er) monads, "reflection without remorse", effect interpreters, etc. Once you need any sort of symbolic reasoning, you drop opaque composition and work with data. This is true in every language, FP or not. People tend to do exactly the right thing already: abandon function combinators and write interpreters over data structures.
- marcosdumay 10y ago> The idea that TCO is needed to "fully" leverage anything is silly. Functional programming relies completely on recursive functions. You just can't do "full" FP without tail call optimizations. Now, I do side with the other poster up there that is talking about jumps. You don't even need jumps actually, you can use inlining and loops too, but they do make the compiler's life easier.
- brandonbloom 10y agoI think that Clojure's success is proof positive that explicit tail recursion and lazy sequences is sufficient to do meaningful FP in the absence of proper tail calls. However, even if you insist that it is somehow not "full", who cares? Clojure is about practicality, not appeasing some platonic ideals. And I say this as some one who would very much appreciate having proper tail calls.
- marcosdumay 10y agoOf course, having lazy sequences and functions for manipulating them is better than not having them. Yet that's such a small part of what FP has to offer that it isn't funny.
- brandonbloom 10y ago¯\_(ツ)_/¯ Extremist views are not particularly useful in engineering, despite their utility is science.