tail calls are a foreign concept to me, and I assume that's because I'm coming from JIT scripts where that's not a common way to think of optimization. Just reading a bit of what they are, it sounds like you're branching within a function to others that return something of the same type - common enough - but get a huge memory/ processing bonus when you branch as long as the sending function doesn't continue? Is that sort of it? I'm really intrigued as to how and where this plays a big role in day to day coding or whether it's just an optimization once you refactor everything at the end.
TCO is a runtime feature that enables code authors to write functions that call out to other functions in such a way that the stack size is not increased. If you’ve ever crossed the `RangeError: Maximum Call Stack Size Exceeded` error, it’s possible that the executed code could’ve benefitted from TCO. TCO is especially invaluable for writing recursive functions (without it, recursion is almost always a bad idea, IMHO).
TCO is technically in the ECMAScript specification (since 2015) but hasn’t been implemented across browsers or runtimes (with a few exceptions).
Check "Using ParentheC to Transform Scheme Programs to C or How to Write Interesting Recursive Programs in a Spartan Host (Program Counter)" for more about trampolines.
Basically it is just another way of doing gotos, while keeeping the abstraction of function calls, without the space required for recursion stack data structures.
Having this as guarantee allows all the control flow concepts to be reduced to recursion and function calls.
A kind of purity when we reduce a programing language to the basic set of primitives that provide the building blocks to create any kind of programming paradigm, this is in a way the beauty of Scheme, moreso than Lisp.
Specifically, loops are a special case (with special syntax) of tail calls for language that don't support tail calls properly.
However as great as tail calls are they can't practically implement all control flow concepts. Eg they aren't really all that great for modelling exceptions, I think.
I would agree with sibling, and expand his comment a bit. Tail calls are just the specialization of continuation passing (or of having reified continuations programmer accessible. Actually, all control flow is the application of a continuation. So while I agree that tail calls are not used as the basis for exceptions, the parent concept of continuation passing does.
Currently, the compiler does a dumb conversion to JS for loop of self tail calls. So if you call `map` on list of 1000000 items, your stack wont blow up. But I understand it is not enough for many non-trivial codebases. We were interested in doing more general TCO, and had some ideas around using trampolines (or iirc detecting mutually recursions and then trying to generate potentially a bit faster code). Had limited time, and was maybe too hopeful that eventually TCO will actually be supported by browsers (as it is part of standard).
It has tail calls, continuations and even green threads (SRFI 18 compliant), and a decentralized module system that can load libraries directly from github and a JS FFI! See this paper for advanced examples that you can copy-paste to the REPL: http://www.iro.umontreal.ca/~feeley/papers/BelangerFeeleyELS...
It's said that the father of LISP, John McCarthy, lamented the W3C's choice of SGML as the basis for HTML : « An environment where the markup, styling and scripting is all s-expression based would be nice. » The {lambda way} project could be an answer, small and simple, a minimal enhanced text-editor: http://lambdaway.free.fr/lambdawalks/
Every lisp (s-expressions really) fan would say most syntaxes/languages would be nicer if they were expressed in s-expressions instead of the c-like aberration most language copy, myself included. I guess McCarthy was simply the first to express that sentiment :)
I'm not a huge fan of the scheme style programming languages although pretty standard even in Go templates because the parenthesis end up with ugly syntax that becomes difficult when using multiple levels, but Racket does seem cool. I found their guide on building web apps to be pretty amazing and I think that is what HN uses for their website.
Having some more syntax for things like maps and destructuring (like Clojure) goes a long way to remove the worst offenders (((like these))), but as others have mentioned, you get used to it, and then you miss it in other places.
You are working with shapes of data, not lines of text. Using tools like Paredit you can get into an incredible flow akin to that of Vi/Emacs mastery, with the added layer that you are moving entire blocks rather than single words (that may or may not end up being valid code).
I don't think so. AFAICT, people do hate parenthesis, no matter how long they use Lips/Scheme. They just simply get used to the clutter.
Also, when writing code, you can spam ")" to close functions/expressions. It takes only few brain cycles if the editor highlights matching parenthesis. This makes it easier to move code around. Copy-paste-))))))...
>I don't think so. AFAICT, people do hate parenthesis, no matter how long they use Lips/Scheme. They just simply get used to the clutter.
People see trees and not parens. People who complain about parens are still stuck in the "code is text" mind set rather than the "code is a tree" mind set.
>Also, when writing code, you can spam ")" to close functions/expressions. It takes only few brain cycles if the editor highlights matching parenthesis. This makes it easier to move code around. Copy-paste-))))))...
We've had editors since the 1970s that can take you to where a matching paren is closed. You then copy/paste the whole function without needing to add or remover parens.
Codes are still text unless you're using tree-based editors. Maintaining tree on text editors requires careful editing and strict practices, which human brains aren't good at. The "tree" will get broken at some point, but, in this school of thought, the recovery strategy is unclear and inconsistent at best. This becomes annoying pretty quickly.
The real tree, at the end of the day, is formed by line breaks and indents, not parenthesis. Codes are also for human consumption after all. Now there are two trees to manage - semantic indentation and parenthesis - which is bad. Luckily we can induce parenthesis from the semantic structure, so we only care about the semantics, and naturally trailing ")" becomes completely redundant.
>Maintaining tree on text editors requires careful editing and strict practices, which human brains aren't good at. The "tree" will get broken at some point, but, in this school of thought, the recovery strategy is unclear and inconsistent at best.
The process in the video still perfectly aligns with my description. Actually, I reached that conclusion by observing people writing Lisp code. That is, when you're writing Lisp code, that's exactly what people next you would see, no matter what you think.
Also, trailing ")"s are clearly a burden, as people do spend their brain cycles to properly match them.
> It isn't. You're not the type of person who lisp is for
You sound like you're right in the middle of Lisp fever, which is fine. Everyone goes through that.
> But I'd be curious to know what language you think uses nothing but line breaks and indents to describe its AST.
You simply didn't get what I was saying. Even when all the parens were stripped off from a Lisp code, you can easily reinsert parens based on line breaks and indents. So people rely more on indentations for correctly putting parens, rather than being cautions w/ every single editing operation.
>That is, when you're writing Lisp code, that's exactly what people next you would see, no matter what you think.
People don't match them. The editor does. Computers are very good at this. Code editing isn't a spectator sport where you can judge how easy something is by watching someone else do it. Try par-edit-mode from emacs, it's a tree editor in a text editor. You'd have your mind blown from this piece of technology from the 90s that uses nothing but plain text to edit a tree using parens.
>You simply didn't get what I was saying. Even when all the parens were stripped off from a Lisp code, you can easily reinsert parens based on line breaks and indents. So people rely more on indentations for correctly putting parens, rather than being cautions w/ every single editing operation.
I think I get picture here that you're probably taking my comment as some old-school Lisp-parenthesis-meme stuff. That's not it. I'm just freaking annoy by that we're using the same shit after decades. Nothing looks cool to me anymore.
> People don't match them. The editor does. Computers are very good at this.
Fixing parenthesis is a semi-automatic operation, performed by people aided by machine. People spend brain cycles on it, still in 2022.
The tree-editing stuffs are in the same line. It's whole purpose is avoid dealing with parens and nested structures, but using it requires in-brain abstraction and getting used to a different set of operations. Extra costs to cognition and operation of the editor. Nothing difficult, but you have other dozens of "nothing difficult" to stack on top of it. Welcome to the world of complexity.
> Try par-edit-mode from emacs
ParEdit is an addition to text editor, and it doesn't block you from introducing mismatched parenthesis. It's actually an important feature, because an editor that forbids this will be more painful to use than manually fixing parens. So we still fix parens in 2022.
Maybe I should compare this to ";" in C-like languages. There are editors, extensions, and formatters that can automatically insert semicolons, but, for whatever reason, semicolons go missing, so people fix it manually, still in 2022. Worse, in Javascript, missing semicolons often causes unintended behaviors, which makes it difficult to debug. Such a nice bug to have in 2022 on a language from 1990s.
Holy Jesus, is this really what we should be dealing with until the last day in our lives? Including all the ancient craps that predates myself? I don't think so.
> did I strip the parens from?
Your example doesn't have any visual structure, and, in practice, we can just refer to the definition of `f` to solve that. Not an actual problem.
What I was talking about is something like this:
defun find-frame-class name
cond
and char= char name 0 #\T
not member name '"TXX" "TXXX" :test #'string=
ecase length name
3 'text-info-frame-v2.2
4 'text-info-frame-v2.3
string= name "COM" 'comment-frame-v2.2
string= name "COMM" 'comment-frame-v2.3
t
ecase length name
3 'generic-frame-v2.2
4 'generic-frame-v2.3
The tree structure is visually represented in the indented code, which is far much easier for human brain to process. You almost immediately notice where parens should go.
To recover parens without lines breaks, you should go over each symbol one by one, tracking their contexts. You know, state is evil.
So the information embedded in code format is redundant to parens. IIRC, there were people who tried to abuse this to eliminate parens. Not really sure how that went.
>ParEdit is an addition to text editor, and it doesn't block you from introducing mismatched parenthesis. It's actually an important feature, because an editor that forbids this will be more painful to use than manually fixing parens. So we still fix parens in 2022.
_It does._ This is like trying to explain red to a very obstinate man wearing a blind fold their whole life.
What you're complaining about is that operators of arbitrary arity need a termination symbol. That is a feature, not a bug. Basically your code is very simple and you're not using higher order functions. At which point you might as well go back to python.
To actually encode the information you're talking using nothing but white space you'd need to do the following:
find-frame-class
name
cond
and
char=
char name 0
#\T
not
member
name
quote
"TXX"
"TXXX"
:test #'string=
ecase
length
name
3
'text-info-frame-v2.2
4
'text-info-frame-v2.3
t
ecase
length
name
3
'generic-frame-v2.2
4
'generic-frame-v2.3
or some such. I lost interest in getting it correct since I wasted a rather long time trying to fit a tree in a 2d page at university. The key point is that a tree can be infinite dimensional and a page isn't. When you know that you rather quickly realize that all syntactic sugar is doomed and you spend your life doing more productive things with it.
We've banned this account. If you don't want to be banned, you're welcome to email hn@ycombinator.com and give us reason to believe that you'll follow the rules in the future. They're here: https://news.ycombinator.com/newsguidelines.html.
There are many examples. But what I'm trying to say is not everything interesting should be done. Maybe there is a legitimate purpose for this. That's what I'm trying to see. But you had to make it personal and attack me. So..
I've never understood how someone who supposedly liked, wanted, and had experience with Scheme ended up creating JavaScript, even being rushed to do so. This isn't a personal judgement. It's just that I don't understand it.
How someone who supposedly liked, wanted and had experience with Scheme ended up creating a language with a function-scoped var binding construct, which then took twenty more years to finally get a block-scoped let.
And to answer the questions every Schemer will have, no the runtime doesn't yet support tail calls or continuations.