Stack orientation is an implementation detail. For example, Joy can be implemented using rewriting - no stack. This is why some prefer to say "concatenative" or "compositional". With quotations and combinators you can code without thinking about the stack.
Expressing yourself with pure composition and without locals or named arguments is the key. It's extremely succinct with no syntactic overhead. Composition makes it very easy to factor out redundancy and to "algebraically" manipulate your code; boiling it down to its essence.
Once you've fallen in love with this point-free style you'll become annoyed by even the slightest composition syntax in other languages (even if just a dot). In concatenative languages, white space is the composition operator.
I'm not sure whether this will quite answer your question, but you'll find that Factor describes itself as a concatenative language first and foremost. It just happens also to have a stack-based execution model. Unfortunately, I can't find Slava's blog post(? or maybe on the Factor Wiki?) talking about this.
The concatenative model basically means that you pass around "hunks of code" (well, that's how you program anyway) and composition looks like concatenation. Operations like currying are also easy to express in a stack-based language since you just pre-compose with code that adds one thing to the stack. In Factor, at least, this is expressed via a word called curry. This makes it much easier to do higher order programming, and mapping over sequences eventually becomes the "obvious way to do it". I came from Lisp and was amazed going back after programming in Factor for a bit that you couldn't do "obvious things" like bi in Lisp. It really does change how you express things.
Incidentally, it's wise not to get too hung up on the whole stack manipulation thing. Using the locals vocabulary (described here: http://docs.factorcode.org/content/article-locals.html), you don't have to worry about shuffling things around. Often there's a neat way to express things without local variables, but I tend to do that second.
One of the important reasons stack-based languages are being developed is because the minimalism of their semantics allows straightforward interpreter and compiler implementation, as well as optimization.
So, one of the practical advantage of such paradigm is that it allows enthusiast people to easily build more complex things and paradigms on top of them.
The Scheme programming language is another example of that: minimalist syntax and semantics, straightforward implementation, and lots of fun!
[EDITED] We already have good answers and I know nothing about the Factor language. However, the favouring of stack usage is a practical advantage of a stack-oriented paradigma and a reason to adopt such paradigma, as asked.
So, I think it is worth listing the advantages of stack usage instead of heap allocation for completeness:
CPU Time -- The time cost of memory allocation in the stack is practically free: doesn't matter if you are allocating one or one thousand integers, all it takes is a stack pointer decrement operation. example
Memory leak -- There are no memory leaks when using the stack only. That happens naturally without additional code overhead to deal with it. The memory used by a function is completely released when returning from each function even on exception handling or using longjmp (no referencing counting, garbage collection, etc).
Fragmentation -- Stacks also avoid memory fragmentation naturally. You can achieve zero fragmentation without any additional code to deal with this like an object pool or slab memory allocation.
Locality -- Data in stack favors the data locality, taking advantage of cache and avoiding page swaps.
Of course, it may be more complicated to implement, depending on your problem, but we shall favor stack over heap always we can in any language. Leave malloc/new to be used only when actually needed (size or lifetime requirements).
For some people it's easier to think in terms of managing stacks than other paradigms. At the very least, doing some hacking in a stack-based language will improve your ability to manage stacks in general.
Aside: in the early days of handheld calculators, they used something called Reverse Polish notation, which is a very simple stack-based postfix notation, and is extremely memory efficient. People who learn to use it efficiently tend to prefer it over algebraic calculation.
发布评论
评论(5)
堆栈方向是一个实现细节。例如,Joy可以使用重写来实现——无堆栈。这就是为什么有些人更喜欢说“连接”或“组合”。使用引号和组合器,您可以在不考虑堆栈的情况下进行编码。
用纯粹的组合来表达自己,没有局部变量或命名参数是关键。它非常简洁,没有语法开销。组合使得分解冗余和“代数地”操作代码变得非常容易;将其归结为本质。
一旦你爱上了这种无点的风格,你就会对其他语言中哪怕是最轻微的组合语法(即使只是一个点)感到恼火。在连接语言中,空格是组合运算符。
Stack orientation is an implementation detail. For example, Joy can be implemented using rewriting - no stack. This is why some prefer to say "concatenative" or "compositional". With quotations and combinators you can code without thinking about the stack.
Expressing yourself with pure composition and without locals or named arguments is the key. It's extremely succinct with no syntactic overhead. Composition makes it very easy to factor out redundancy and to "algebraically" manipulate your code; boiling it down to its essence.
Once you've fallen in love with this point-free style you'll become annoyed by even the slightest composition syntax in other languages (even if just a dot). In concatenative languages, white space is the composition operator.
我不确定这是否能完全回答您的问题,但您会发现 Factor 将自己描述为 连接语言首先。它恰好也有一个基于堆栈的执行模型。不幸的是,我找不到 Slava 的博客文章(?或者可能在 Factor Wiki 上?)谈论这个。
连接模型基本上意味着您传递“大量代码”(好吧,这就是您编程的方式)并且组合看起来像连接。像柯里化这样的操作也很容易用基于堆栈的语言来表达,因为您只需预先编写将一项内容添加到堆栈中的代码。至少在 Factor 中,这是通过一个名为
curry
。这使得进行高阶编程变得更加容易,并且序列上的映射最终成为“显而易见的方法”。我来自 Lisp,在 Factor 中编程一段时间后,我很惊讶地发现你无法做“明显的事情”,比如
bi
。它确实改变了你表达事物的方式。顺便说一句,明智的做法是不要太沉迷于整个堆栈操作的事情。使用
locals
词汇(此处描述:http://docs. Factorcode.org/content/article-locals.html),您不必担心混乱的事情。通常有一种简洁的方法可以在没有局部变量的情况下表达事物,但我倾向于其次这样做。I'm not sure whether this will quite answer your question, but you'll find that Factor describes itself as a concatenative language first and foremost. It just happens also to have a stack-based execution model. Unfortunately, I can't find Slava's blog post(? or maybe on the Factor Wiki?) talking about this.
The concatenative model basically means that you pass around "hunks of code" (well, that's how you program anyway) and composition looks like concatenation. Operations like currying are also easy to express in a stack-based language since you just pre-compose with code that adds one thing to the stack. In Factor, at least, this is expressed via a word called
curry
. This makes it much easier to do higher order programming, and mapping over sequences eventually becomes the "obvious way to do it". I came from Lisp and was amazed going back after programming in Factor for a bit that you couldn't do "obvious things" likebi
in Lisp. It really does change how you express things.Incidentally, it's wise not to get too hung up on the whole stack manipulation thing. Using the
locals
vocabulary (described here: http://docs.factorcode.org/content/article-locals.html), you don't have to worry about shuffling things around. Often there's a neat way to express things without local variables, but I tend to do that second.开发基于堆栈的语言的重要原因之一是其语义的极简主义允许简单的解释器和编译器实现以及优化。
因此,这种范式的实际优势之一是它允许爱好者轻松地在其之上构建更复杂的事物和范式。
Scheme 编程语言是另一个例子:极简的语法和语义、简单的实现以及很多乐趣!
One of the important reasons stack-based languages are being developed is because the minimalism of their semantics allows straightforward interpreter and compiler implementation, as well as optimization.
So, one of the practical advantage of such paradigm is that it allows enthusiast people to easily build more complex things and paradigms on top of them.
The Scheme programming language is another example of that: minimalist syntax and semantics, straightforward implementation, and lots of fun!
[编辑] 我们已经有了很好的答案,但我对 Factor 语言一无所知。然而,正如所要求的,对堆栈使用的青睐是面向堆栈范式的实际优势,也是采用这种范式的原因。
因此,为了完整性,我认为值得列出堆栈使用而不是堆分配的优点:
当然,根据您的问题,实现起来可能会更复杂,但在任何语言中,我们总是会优先选择堆栈而不是堆。仅在实际需要时(大小或生命周期要求)才使用 malloc/new。
[EDITED] We already have good answers and I know nothing about the Factor language. However, the favouring of stack usage is a practical advantage of a stack-oriented paradigma and a reason to adopt such paradigma, as asked.
So, I think it is worth listing the advantages of stack usage instead of heap allocation for completeness:
Of course, it may be more complicated to implement, depending on your problem, but we shall favor stack over heap always we can in any language. Leave malloc/new to be used only when actually needed (size or lifetime requirements).
对于某些人来说,管理堆栈比其他范例更容易思考。至少,使用基于堆栈的语言进行一些黑客攻击将提高您管理堆栈的能力。
另外:在手持式计算器的早期,他们使用了一种叫做逆波兰表示法的东西,这是一种非常简单的基于堆栈的后缀表示法,并且内存效率极高。学会有效使用它的人往往更喜欢它而不是代数计算。
For some people it's easier to think in terms of managing stacks than other paradigms. At the very least, doing some hacking in a stack-based language will improve your ability to manage stacks in general.
Aside: in the early days of handheld calculators, they used something called Reverse Polish notation, which is a very simple stack-based postfix notation, and is extremely memory efficient. People who learn to use it efficiently tend to prefer it over algebraic calculation.