您实质上要问的是计算能力与通常所说的语言(或计算系统)的表达能力(或只是表达能力)之间的差异。
计算能力
在计算能力指的是什么样的问题,语言可以计算。最著名的计算能力类别是等效于Universal Turing Machine的类别。还有许多其他计算系统,例如随机存取机,λ演算,SK组合器演算,μ递归函数,WHILE
程序等。事实证明,所有这些都可以互相模拟,这意味着它们都具有相同的计算能力。
这产生了Church-Turing论文(以创建λ微积分的Alonzo Church和创建Universal Turing Machine的Alan Turing的名字命名)。Church-Turing-Thesis是关于可计算性的假设,有两个方面:
- 所有具有通用计算能力的计算系统都具有同样强大的功能,并且
- 遵循算法的人可以精确计算出图灵机(以及任何其他系统)可以计算的功能。
不过,第二点在思维哲学领域比计算机科学更重要。
但是,Church-Turing-Thesis 没有说两点,它们与您的问题非常相关:
- 各种模拟的效率如何,以及
- 如何方便问题的编码。
(1)的一个简单示例:在随机存取机上,复制数组所花费的时间与数组的长度成正比。但是,在Turing Machine上,它花费的时间与阵列长度的平方成正比,因为Turing Machine没有随机存储器访问权限,因此一次只能在磁带上移动一个单元。因此,它需要在数组的n 个元素上移动n次才能复制它们。因此,即使在渐近情况下,我们尝试从实现细节中抽象出来,不同的计算模型也可能具有不同的性能特征。
(2)的例子比比皆是:λ演算和Python都是图灵完备的。但是,您愿意使用Python还是λ微积分编写程序?
到目前为止,我还绕过了第三个皱纹:所有这些原始系统都是由逻辑学家,哲学家或数学家设计的,而不是由计算机科学家设计的……只是因为计算机以及计算机科学都不存在。所有这些都可以追溯到1930年代初,甚至早于Konrad Zuse的第一个实验(无论如何都不是可编程的和/或Turing-complete)。他们只谈论“自然数上的可计算函数”。
事实证明,现在有很多可以表达为自然数的函数–毕竟,我们的现代计算机所获得的收益远不止于此(基本上是数字0和1的3-4个函数,仅此而已) ),但是,例如,操作系统计算什么功能?
与环境交互的I / O副作用这一概念没有被“自然数函数”的思想所抓住。但是,这是很重要的,因为正如Simon Peyton Jones曾经说过的:“所有没有副作用的纯函数都会使您的CPU变得炙手可热”,听众对此回答说:“实际上,这是一面。效果也一样!”
Idris的设计师Edwin Brady(只有一半)开玩笑地(我不知道他是否发明过)用“俄罗斯方块完成”一词来表达“可以对自然数计算任何可计算函数”和“可以用于编写与环境交互的重要程序”。更具有讽刺意味的是,他通过在Idris中实现了Space Invaders克隆来证明了这一点,但是他说,他有信心Tetris可以沦为Space Invaders。
要指出的另一件事情是,不仅是图灵等价不一定足够的谈实际编写“有用”的程序,它也可能OTOH甚至不necesssary。例如SQL,只是变得图灵等效采用ANSI SQL:1999年,但它仍然是之前有用。实际上,有些人可能会争辩说,使之等效于Turing并没有增加其实用性。有许多图灵等效的领域特定语言。数据描述语言通常不是(也不应该)。总语言显然不能与图灵等效,但是您仍然可以在其中编写事件循环,Web服务器或操作系统。也有与图灵等效的语言,但实际上被认为是错误的。
因此,总的来说,图灵等效性并不是特别有趣,除非您想静态分析程序。
表现力
假设我们的计算系统具有足够强大的计算能力甚至根本无法解决我们的问题,那么接下来要做的就是以某种形式表示该系统的算法来解决该问题。换句话说:我们需要用某种计算机语言编写程序。这就是表达能力的概念。
本质上,它是指用我们特定的编程语言编写我们的程序是多么“轻松”或“令人愉快”。如您所见,该概念非常模糊,主观,而且比技术更具有心理性。
但是,尝试进行更精确的定义。最著名的(也是我所知道的最严谨的)是Matthias Felleisen在他的论文《编程语言的表现力》中(前两页进行了简短的介绍,而本文的其余部分更加生动)。
主要的直觉是:将程序从一种语言翻译为另一种语言时,您需要进行的某些更改是本地包含的(例如,将FOR
循环转换为WHILE
循环或将循环转换为条件GOTO
s),而有些则需要更改全局变量程序的结构。
如果仅通过局部转换就可以将一种语言的一种功能替换为另一种语言的不同功能,则可以说这些功能对表达能力没有影响。这就是所谓的语法糖。
另一方面,如果需要更改程序的全局结构,则可以说您要翻译的语言无法表达该功能。并且您要翻译的语言据说更具表现力(就此功能而言)。
请注意,这给出了可客观地衡量表达的定义。还要注意,该概念与上下文有关,并且是可比较的。所以,如果在语言中的每个程序一个可以被翻译成语言乙仅有局部的变化,并且在语言至少一个程序乙可以不被翻译成一个仅有局部的变化,那么语言乙是严格比语言更有表现力一种。但是,更可能的情况是,可以同时翻译两种语言的许多程序,但是有些程序无法将两种语言翻译成另一种语言。这意味着两种语言都不比另一种语言更具表达力,它们只是具有不同的功能,可以用不同的方式表达不同的程序。
这给出了“更具表现力”的含义的正式定义,但仍未捕捉到现象背后的心理观念。例如,根据此模型,语法糖不会增加语言的表达能力,因为它只能使用局部更改来翻译。但是,我们从经验中知道,有FOR
,WHILE
和IF
可用的,即使他们是有条件的只是语法糖GOTO
品牌表达我们的意图更加容易。
事实是,不同的语言具有不同的功能,这些特征使表达对问题的不同思考方式变得更容易或更困难。有些人可能会发现一种更容易表达其意图的方式,而另一些人则可能会发现另一种方式。
我在StackOverflow上的Ruby标记中发现了一个示例:许多遵循Ruby标记的用户声称,循环比递归更容易理解,而递归仅适用于高级功能程序员,而循环对于新手则更直观,但是我看到了多种情况完整的新手,他们会直观地编写如下代码:
def rock_paper_scissors
get_user_input
determine_outcome
print_winner
rock_paper_scissors # start from the top
end
这通常导致几个人评论“这不起作用”和“他们做错了”,而“正确方法”是这样的:
def rock_paper_scissors
loop do
get_user_input
determine_outcome
print_winner
end
end
因此,显然,对于某些人来说,尾循环是一种比循环构造更自然的表达“循环”概念的方式。
摘要
两种语言与图灵等效的事实说明了一件事,那就是一件事:它们可以像图灵机一样在自然数上计算相同的一组函数。而已。
它没有说出它们计算这些函数的速度。它没有说明易于表达这些功能的任何内容。除了计算自然数上的功能(例如,链接到C库,从用户读取输入,将输出写入屏幕外)外,它什么也没说。
这是否意味着即使每种语言都已完成,每种编程语言可以准确解决的问题类别也会因语言而异?
是。
- 术语“ Turing-complete”(仅涉及自然数的计算功能)没有涵盖这些问题,例如在屏幕上打印。两种语言可以是图灵完备的,但是一种可以允许在屏幕上打印,而另一种则不能。
- 即使两种语言都可以解决相同的问题,也无法说明编码的复杂程度以及表达这种编码的难易程度。例如,C可以解决Haskell可以解决的所有问题,只需用C编写Haskell解释器即可。但是您必须首先编写Haskell解释器才能以这种方式解决问题!