I've read the Wikipedia article on concatenative languages, and I am now more confused than I was when I started. :-)
What is a concatenative language in stupid people terms?
I've read the Wikipedia article on concatenative languages, and I am now more confused than I was when I started. :-)
What is a concatenative language in stupid people terms?
In normal programming languages, you have variables which can be defined freely and you call methods using these variables as arguments. These are simple to understand but somewhat limited. Often, it is hard to reuse an existing method because you simply can't map the existing variables into the parameters the method needs or the method A calls another method B and A would be perfect for you if you could only replace the call to B with a call to C.
Concatenative language use a fixed data structure to save values (usually a stack or a list). There are no variables. This means that many methods and functions have the same "API": They work on something which someone else left on the stack. Plus code itself is thought to be "data", i.e. it is common to write code which can modify itself or which accepts other code as a "parameter" (i.e. as an element on the stack).
These attributes make this languages perfect for chaining existing code to create something new. Reuse is built in. You can write a function which accepts a list and a piece of code and calls the code for each item in the list. This will now work on any kind of data as long it's behaves like a list: results from a database, a row of pixels from an image, characters in a string, etc.
The biggest problem is that you have no hint what's going on. There are only a couple of data types (list, string, number), so everything gets mapped to that. When you get a piece of data, you usually don't care what it is or where it comes from. But that makes it hard to follow data through the code to see what is happening to it.
I believe it takes a certain set of mind to use the languages successfully. They are not for everyone.
[EDIT] Forth has some penetration but not that much. You can find PostScript in any modern laser printer. So they are niche languages.
From a functional level, they are at par with LISP, C-like languages and SQL: All of them are Turing Complete, so you can compute anything. It's just a matter of how much code you have to write. Some things are more simple in LISP, some are more simple in C, some are more simple in query languages. The question which is "better" is futile unless you have a context.
首先,我要反驳 Norman Ramsey 的断言,即没有理论。
连接语言理论
连接语言是一种函数式编程语言,其中默认操作(当两个术语并排时发生的情况)是函数组合而不是函数应用。它是如此简单。
因此,例如在 SKI Combinator Calculus(最简单的函数式语言之一)中,两个术语并排等效于将第一个术语应用于第二个术语。例如:S K K
等价于S(K)(K)
。
在连接语言S K K
中相当于S . K . K
在 Haskell 中。
那么有什么大不了的
纯连接语言具有一个有趣的特性,即术语的求值顺序无关紧要。在连接语言(S K) K
中与S (K K)
. 这不适用于 SKI 微积分或任何其他基于函数应用的函数式编程语言。
这一观察结果有趣的一个原因是,它揭示了在以函数组合而不是应用程序表示的代码评估中并行化的机会。
现在对于现实世界
支持高阶函数的基于堆栈的语言的语义可以使用串联演算来解释。您只需将每个术语(命令/表达式/子程序)映射为将函数作为输入并返回函数作为输出的函数。整个程序实际上是一个单栈转换函数。
现实情况是,现实世界中的事物总是被扭曲的(例如,FORTH 有一个全局字典,PostScript 在评估顺序很重要的地方做了奇怪的事情)。大多数实用的编程语言并不完全符合理论模型。
最后的话
我不认为一个典型的程序员或 8 岁的孩子应该担心什么是连接语言。我也没有发现它对鸽子洞编程语言特别有用,因为它是 X 型或 Y 型。
在阅读了http://concatenative.org/wiki/view/Concatenative%20language并借鉴了我十几岁时摆弄 Forth 的记忆后,我相信串联编程的关键在于:
从上面的网页中查看这些报价:
有两个术语被抛出,堆栈语言和连接语言。两者都定义了相似但不相等的语言类别。但在大多数情况下,它们是相同的。
今天广泛使用的大多数语言都是应用语言:语言的核心结构是某种形式的函数调用,其中一个函数应用于一组参数,其中每个参数本身就是函数调用的结果,一个函数的名称变量或常数。在堆栈语言中,只需编写函数名即可进行函数调用;参数是隐式的,并且在调用时它们必须已经在堆栈上。函数调用的结果(如果有)然后在函数返回后留在堆栈中,以供下一个函数使用,依此类推。因为函数是通过简单地提及它们的名字来调用而没有任何额外的语法,所以 Forth 和 Factor 将函数称为“单词”,因为在语法中它们实际上只是单词。
这与将其功能直接应用于特定变量的应用语言形成对比。
示例:将两个数字相加。
适用语言:
int foo(int a, int b)
{
return a + b;
}
var c = 4;
var d = 3;
var g = foo(c,d);
连接语言(我编的,应该和 Forth 类似……;))
push 4
push 3
+
pop
虽然我不认为连接语言 = 堆栈语言,但正如作者在上面指出的那样,它看起来很相似。
我认为主要思想是 1. 我们可以通过将其他程序简单地连接在一起来创建新程序。
此外,2. 程序的任何随机块都是有效的函数(或子程序)。
旧的纯 RPN Forth 具有这些属性,不包括任何随机的非 RPN 语法。
在程序 1 2 + 3 * 中,子程序 + 3 * 需要 2 个 args,并给出 1 个结果。子程序 2 接受 0 个参数并返回 1 个结果。任何块都是一个函数,这很好!
您可以通过将两个或多个其他函数组合在一起来创建新函数,也可以选择使用一点胶水。如果类型匹配,它将工作得最好!
这些想法真的很好,我们重视简单。
它不限于 RPN Forth 风格的串行语言,也不限于命令式或函数式编程。这两个想法也适用于图形语言,其中程序单元可能是例如函数、过程、关系或过程。
在通信进程网络中,每个子网络都可以像一个进程一样工作。
在数学关系图中,每个子图都是有效的关系。
这些结构是“连接的”,我们可以以任何方式将它们分开(画圆),并以多种方式将它们连接在一起(画线)。
嗯,我就是这么看的。我确信我错过了串联阵营的许多其他好主意。虽然我热衷于图形编程,但我对这种关注连接并不陌生。
我对串联编程的务实(和主观)定义(现在,您可以避免阅读其余部分):
-> 以极端方式组合函数(使用反向波兰表示法 (RPN) 语法):
( Forth code )
: fib
dup 2 <= if
drop 1
else
dup 1 - recurse
swap 2 - recurse +
then ;
-> 一切都是函数,或者至少可以是函数:
( Forth code )
: 1 1 ; \ define a function 1 to push the literal number 1 on stack
-> 参数通过函数隐式传递(好吧,这似乎是默认编程的定义),但是,在 Forth 中是这样的:
a b c
可能在 Lisp 中:
(c a b)
(c (b a))
(c (b (a)))
因此,很容易生成模棱两可的代码......您可以编写将 xt(执行令牌)推送到堆栈上的定义,并为“执行”定义一个小别名:
( Forth code )
: <- execute ; \ apply function
所以,你会得到:
a b c <- \ Lisp: (c a b)
a b <- c <- \ Lisp: (c (b a))
a <- b <- c <- \ Lisp: (c (b (a)))
You can't explain a language, just get one (Factor, preferably) and try some tutorials on it. Tutorials are better than Stack Overflow answers.
对于您的简单问题,这是一个主观和有争议的答案。
我查看了这篇文章和几个相关的网页。网页自称没有真正的理论,所以难怪人们很难想出一个精确且易于理解的定义。我想说,目前,将语言分类为“连接”或“非连接”是没有用的。
对我来说,这似乎是一个让Manfred von Thun有机会挂帽子的术语,但可能对其他程序员没有用处。
虽然 PostScript 和 Forth 值得研究,但我看不出 Manfred von Thun 的 Joy 编程语言有什么特别新的或有趣的东西。事实上,如果你阅读了 Chris Okasaki 的关于Haskell 中嵌入后缀语言的技术的论文,你可以在相对于 Joy 而言是完全主流的环境中尝试所有这些东西。
所以我的回答是没有简单的解释,因为没有成熟的理论支持连接语言的想法。(正如爱因斯坦和费曼所说,如果你不能向大学新生解释你的想法,你就不会真正理解它。)我会进一步说,尽管学习其中一些语言,如 Forth 和 PostScript,是一种很好地利用时间,试图弄清楚人们说“连接”时的确切含义可能是浪费你的时间。