为什么赋值运算符分配到左侧?


47

我刚开始教一个朋友编程(我们正在使用Python),当我们开始讨论变量的创建和赋值运算符时,她问为什么将右边的值分配给左边的名称,反之亦然。

我以前并没有考虑太多,因为它对我来说似乎很自然,但是她说从左到右对她来说似乎更自然,因为那是我们大多数人阅读自然语言的方式。

我考虑了一下,并得出结论,它使代码更易于阅读,因为分配给它们的名称(程序员将需要重用)很容易看到,并与左侧对齐。

aligned = 2
on = 'foo' + 'bar' + 'foobar'
the = 5.0 / 2
left = 2 + 5

相对于:

2 = aligned 
'foo' + 'bar' + 'foobar' = on
5.0 / 2 = the 
2 + 5 = right 

# What were the names again...?

现在,我想知道该标准是否还有其他原因。它背后有历史吗?还是出于某种技术原因,这是一个不错的选择(我对编译器了解不多)?是否有分配给右侧的编程语言?


15
R可以分配给右侧(value -> variable)。

也许这是由于变量名错误造成的?“ numAligned是2”和“ chickensLeft是2 + 5”怎么样?
工作

18
是你朋友的名字吗?
阿德里安

1
如果她开始对此抱怨,我想知道当她看到C ++&co时会做什么。
BlackBear

3
附带说明:汗学院(Khan Academy)为初学者提供了一些关于Python的课程:khanacademy.org/#computer-science,而Google有一些更高级的课程:code.google.com/edu/languages/google-python-class/set- up.html
林登·福克斯

Answers:


56

同上@paxdiablo。早期的编程语言是由数学家编写的,实际上都是。在数学中,按照她自己的原理-从左到右阅读-在它的工作方式上是有意义的。

x = 2y-4。

在数学中,您会这样说:令x等于2y -4。

另外,即使在代数中,您也可以这样做。在求解变量的方程式时,可以将要求解的变量隔离到左侧。即y = mx + b;

此外,一旦整个语言家族(例如C族)具有某种语法,更改成本就更高。


19
@FarmBoy:在数学中,赋值和相等是相同的,因为公式中没有序列,而计算机中也没有序列。(a等于b,同时b等于a)
Petruza 2011年

1
@FB,但某些单一分配功能语言(例如Erlang)除外。分配和保证平等与数学相同
Peer Stritzinger

18
@Petruza不,在数学分配和相等性上不是一回事。如果我说“让x = 2y-3”,则不同于“因此x = 2y-3”。我数学上,通常情况下区分它们。由于“引起争议的评论”广受赞誉,因此我要说我有博士学位。在数学上,我对此很确定。
埃里克·威尔逊

2
我不知道在博士附近的任何地方的数学,我的意思是,由于没有顺序性,因此无论是赋值还是相等,数学都没有执行顺序,这与编程不同,在编程中,赋值的两面都是在某个时间点不同,并且最终在其他时间点相等。但是在数学中,在let a be...没有时间的作业中,作业的两面也相等,因此作业实际上是相等的,也难怪为什么两者都使用相同的符号:=
Petruza 2011年

5
@Petruzza -但有顺序性。数学文档与其他任何文档一样,是从头到尾编写的。如果我x = 1在第一章中断言,但x = 2在第二章中断言,那并不是什么可怕的矛盾-每个断言仅适用于特定的上下文。命令式编程的区别部分是消除障碍(我们不需要更改上下文),部分是关于实现和实用性。
2011年

26

BASIC,最早的计算机语言之一是“适当”的形式:

10 LET AREA = HEIGHT * WIDTH

符合指定变量的数学思维方式,例如“让H为对象的高度”。

COBOL它的COMPUTE陈述也很相似。与许多处理方式一样,它可能只是通过多种语言继承的任意决定。


7
我认为当程序行被视为“语句”而非“操作”时,这种形式更为自然。如上所示I declare that X must equal THIS,而不是更线性Evaluate THIS and store it in X
voithos 2011年

等等,BASIC是一种“早期”计算机语言?
亚历克斯·费曼

2
@Alex考虑到它始于1960年代,所以我认为这还为时过早。
本·理查兹

1
另一方面,在COBOL中,您可以编写MULTIPLY HEIGHT BY WIDTH GIVING AREA,因此获取结果的变量位于语句的最右侧。
user281377 2011年

25

实际上,右边有一种编程语言:TI-BASIC!不仅如此,它也不使用'='作为赋值运算符,而是使用称为“ STO”运算符的箭头。

例子:

5→A
(A + 3)→B
(A - B)→C

在上面的示例中,声明了三个变量并为其提供了值。A为5,B为8,C为-3。可以将第一个声明/赋值读作“将5存储为A”。

至于为什么TI-BASIC使用这样的系统进行分配,我将其归因于它是因为它是计算器的一种编程语言。计算数字,TI计算器上的“ STO”运算符最常用于正常的计算器操作中。如果这是用户想要记住的数字,则他们将按下“ STO”按钮,并且caclulator会提示他们输入名称(自动使用字母锁定,以便击键产生字母而不是数字):

Sin(7 + Cos(3))
                    -.26979276
Ans→{variable name}
                    -.26979276

用户可以随意选择该变量的名称。必须打开字母锁定,键入名称,然后按“ STO”,然后按“ Ans”键对于正常操作来说太麻烦了。由于TI-BASIC中所有计算器功能均可用,因此与“ STO”执行相同任务时未添加任何其他赋值运算符,尽管与大多数其他语言相比是倒退的。

(轶事:TI-BASIC是我学习的第一门语言,因此,当我在大学里第一次学习Java时,我觉得分配给LEFT似乎是不寻常且“落后”的!)


+1我完全忘记了!TI Basic也是我的母语,但是我不记得这个细节。
barjak 2011年

实际上,STO操作员更接近机器的工作方式以及任何语言的实际工作方式。首先计算该值,然后将其存储在内存中。
Kratz,

15

启发式1: 在设计一种语言时,遇到多种可能的工作方式,请选择最常见,最直观的一种,否则最终您将获得Perl +。

现在,它如何变得自然(至少对于说英语的人来说)?让我们看看我们如何用英语写/说事物:

史蒂文(Steven)现在10岁(史蒂文现在只有10岁)。我的体重超过190磅(而我的体重超过190磅)。

在代码中:

steven = 10
i > 190

以下内容听起来更自然:

“如果玛丽18岁,那么她可以吃糖果”。“如果我还不到21岁,那么我会请哥哥给我龙舌兰酒。”

if (mary == 18) { ... }
if (i < 21) { ... }

比:

“如果18岁的玛丽是……”“如果21岁大于我的年龄……”

现在的代码:

if (18 == mary) { ... }
if (21 > i) { ... }

请注意,这对于程序员和讲英语的人都是不自然的。句子听起来像是yoda-speak,而代码被昵称为yoda-conditions。这些在C ++中可能会有所帮助,但是我相信大多数人都会同意:如果编译器可以完成繁重的工作并减轻对yoda条件的需求,那么生活会更轻松一些。

当然,任何人都可以习惯。例如,数字81表示为:

八十一(英语)八十一(西班牙)一八十(德语)。

最后有4个!= 24种有效的俄语俄语“在桌子上躺着苹果”的表达方式-顺序(几乎)无关紧要,只不过“开”必须与“桌子”连在一起。因此,例如,如果您是说俄语的母语的人,那么您可能不在乎一个人写作a = 10还是10 = a因为两者看起来自然而然。

尽管语言学是一门引人入胜的学科,但我从未正式学习过它,也不知道那么多语言。希望我提供了足够的反例。


4
...并且在法语中,81被称为“四十二乘以21” ... :)
Martin Sojka,

1
@马丁,我相信丹麦语非常相似。
的CVn

7
@马丁这真是奇怪,因为四次21是84
彼得·奥尔森

6
@Peter:您的括号写错了,这是(four times twenty) one
SingleNegationElimination

4
@Job:读到你的“如果18岁的玛丽是……”,我不可避免地想起Yoda的话:“当你达到900岁时,看起来不会那么好,嗯?” 以绝地归来:-)
joriki 2011年

11

它始于1950年代的FORTRAN。其中FORTRAN是FORmula TRANslation的缩写-所讨论的公式是简单的代数方程式,按照惯例,它们始终分配给左侧。

另一方面,它接近当代的COBOL就是英语风格的,并被分配给了右侧(主要是!)。

MOVE 1 TO COUNTER.
ADD +1 TO LINE-CNT.
MULTIPLY QTY BY PRICE GIVING ITEM-PRICE.

我认为这是最好的示例,因为它完美地说明了一种语言,该语言对于普通英语使用者来说是可读的,但具有正确的分配。我说这很重要,因为有很多人用英语说,只有从左到右阅读才能使分配有意义,这绝对是不正确的。
约书亚树篱

5

好吧,正如@ diceguyd30指出的那样,有两种表示法。

  • <Identifier> = <Value>表示“让标识符成为 ”。或扩展它:将变量Identifier定义(或重新定义)为Value
  • <Value> -> <Identifier>表示“将存储到标识符 ”。或将其扩展:将Value放入Identifier指定的位置。

当然,通常来说,标识符实际上可以是任何L值。

第一种方法尊重变量的抽象概念,第二种方法更多地关于实际存储。

请注意,第一种方法在没有赋值的语言中也很常见。还要注意,变量定义和分配都比较接近<Type> <Identifier> = <Value>对比<Identifier> = <Value>


3

如前所述,所有早期的计算机语言都可以很好地工作。例如FORTRAN,它比BASIC诞生了很多年。

实际上,将赋值变量放在赋值表达式的左侧非常有意义。在某些语言中,“ SAME NAME”可能有几个不同的重载例程,它们返回不同类型的结果。通过让编译器首先查看分配的变量的类型,它知道要调用的重载例程,或从(例如)整数转换为浮点数时生成的隐式强制转换。这只是一个简单的解释,但希望您能理解。


2
我理解您的解释,但是编译器难道不能在语句结尾前一直向前看吗?
voithos 2011年

这可能会使词法分析器在当今的语言中变得更简单,但是当这种语法是新语法时,有多少种编程语言甚至支持命名方法,更不用说方法重载了?
的CVn

2
嗨@voithos。是的-编译器可以展望未来,但是在编写编译器的初期,这可能是一个无法接受的复杂程度-通常是手工编码的汇编器!我认为将分配的变量放在左边是一个务实的选择:人和机器都更容易解析。
Dave Jewell

我认为将任务分配给该权限将是微不足道的。当像3 + 4 == 6 + 7之类的表达式时,在运算符之前先评估双方,因为该语言是递归定义的。语言元素“变量=表达式”可以很容易地更改为“表达式=变量”。是否导致歧义情况取决于语言的其余部分。
Kratz,

@Kratz-现在对于编译器当然是正确的,但是对于使用令牌化源代码的非常古老的解释型语言来说,可能存在一个小问题。OTOH,可能更喜欢右侧变量而不是左侧变量。
2011年

3

它可能是早期解析算法的残余。请记住,LR解析仅是在1965年发明的,很可能是LL解析器遇到了麻烦(在当时机器的时间和空间限制内)。考虑:

identifier = function();
function();

两者显然已与第二个令牌区分开。另一方面,

function() = identifier;
function();

不好玩。当您开始嵌套分配表达式时,情况会变得更糟。

function(prev_identifier = expression) = identifier;
function(prev_identifier = expression);

当然,更容易为机器消除歧义也意味着更容易为人类消除歧义。另一个简单的示例是搜索任何给定标识符的初始化。

identifier1 = expressionOfAnArbitraryLength;
identifier2 = expressionOfAReallyReallyReallyArbitraryLength;
identifier3 = expression;
identifier4 = AlongLineExpressionWithAFunctionCallWithAssignment(
    identifier = expr);

容易,只需向上看左侧。另一方面,右侧

expressionOfAnArbitraryLength = identifier1;
expressionOfAReallyReallyReallyArbitraryLength = identifier2;
expression = identifier3;
AlongLineExpressionWithAFunctionCallWithAssignment(expr = identifier
    ) = identifier4;

特别是当您不能grep打卡时,要查找所需的标识符就困难得多。


正是我所想到的要点。
voithos,2011年

2

汇编语言将目的地作为左侧操作码的一部分。高级语言倾向于遵循先前语言的约定。

当您看到=(或:=对于Pascalish方言)时,可以将其发音为is assigned the value,那么从左到右的性质就有意义(因为在大多数语言中我们也从左到右阅读)。由于编程语言主要是由从左到右阅读的人们开发的,因此约定俗成。

这是一种路径依赖。我想,如果计算机编程是由说希伯来语或阿拉伯语(或其他从右到左语言)的人发明的,那么我怀疑我们会将目的地放在右边。


是的,但是我怀疑编辑器中的文本也会右对齐...
voithos 2011年

8
您不能像汇编语言那样一概而论。它们根据目标操作数的位置而有所不同。
quick_now 2011年

2
@quickly_now:对;实际上,大多数原始机器语言(按当今的标准甚至没有汇编程序)甚至没有目的地,因为通常只有一两个通用累加器。除“存储”操作码外,大多数操作都将累加器隐含为目的地,“操作”操作码仅指定存储器地址,而不指定源(即累加器)。我真的认为这对类似ALGOL的语言的赋值语法没有任何影响。
哈维尔

3
@Tangurena- 某些汇编语言在左边很沮丧。不是操作码(这是汇编的目标代码),而是指令助记符的参数列表的左侧。但是,其他人的目的地在右边。mov.b #255, d0例如,在68000汇编程序中,您将编写,其中d0的寄存器要分配到哪里。较旧的汇编器每条指令只有一个参数。在6502 LDA #255(Load Accumulator)中,您可以辩称,A它在左侧,但在STA wherever(Store Accumulator)中也位于左侧。
2011年

2
分配高级语言,甚至还开发了Intel 4004(8086家族的4位终极祖先,介于8008和8080之间)。如果您假设8086系列代表了50年代及更早的汇编程序所做的事情,那么我非常怀疑这是真的。
Steve314,2011年

2

值得一提的是,COBOL中的大多数语句都是从左到右读取的,因此两个操作数首先被命名,而目的地最后被命名,例如:multiply salary by rate giving tax

但是,我不会建议您的学生可能更喜欢COBOL,因为担心(很正确)我会被标记为做出这样低,粗俗,无味的评论!:-)


1

她说从左到右对她来说似乎更自然,因为那是我们大多数人阅读自然语言的方式。

我认为这是一个错误。一方面,您可以说“将10赋给x”或“将10赋给x”。另一方面,您可以说“将x设置为10”或“ x变为10”。

换句话说,根据您对动词的选择,分配给变量可能是也可能不是主语,也可能不在左侧。因此,“什么是自然的”完全取决于您习惯性地选择措辞来表示作业。


0

在伪代码中,赋值运算符通常写在右边。例如

2*sqrt(x)/(3+y) -> z

在卡西欧计算器中,即使是非可编程变量,赋值变量也会显示在右侧

A+2B → C

在Forth中,变量也位于右侧

expression variable !

在x86中,Intel语法的目标位置在左侧,但GAS语法使顺序相反,这使许多人感到困惑,尤其是在有关参数顺序(如减法或比较)的说明上。这些说明在2种不同的方言中是相同的

mov rax, rbx    ; Intel syntax
movq %rbx, %rax ; GAS syntax

他们都将rbx中的值移动到rax。我知道没有其他汇编语言像GAS这样在右边写目标。

一些平台将表达式放在左边,变量放在右边:

MOVE expression TO variable      COBOL
expression → variable            TI-BASIC, Casio BASIC
expression -> variable           BETA, R
put expression into variable     LiveCode

https://zh.wikipedia.org/wiki/工作分配_%28computer_science%29#Notation

大多数语言将值赋给左侧,原因之一是易于对齐运算符,更易于读取和识别变量,因为赋值运算符和变量的位置在行中不会发生巨大变化,并且更易于阅读“让变量成为一些值”。

但是,有些人喜欢说“将值x移到y”并在右侧写变量。


-1

我认为它遵循一种逻辑思维方式。
首先必须有一个框(变量),然后将一个对象(值)放入其中。
您不要将物体放在空中,然后在其周围放一个盒子。


2
是的你是。在大多数语言中,右侧先于左侧。
哈维尔

3
它是“在道路右侧行驶”类型的事物。看来合乎逻辑,但这只是因为它始终是您做事的方式。所有上级国家都向左行驶。
James Anderson

1
@JamesAnderson优越的国家?:o
nawfal 2014年

没错,从左到右的书写系统是罗马字母,这是合乎逻辑的,我想几乎所有的编程语言都使用它,即使不是全部。
Petruza 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.