つい最近(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...?
この規格には他にも理由があるのでしょうか。その背後に歴史はありますか?それとも、これが適切なオプションである技術的な理由はありますか(コンパイラについてはあまり知りません)。そして、右側に割り当てられているプログラミング言語はありますか?
同上@paxdiablo。初期のプログラミング言語は数学者によって書かれました-実際にはすべてそうでした。数学では、左から右に読むという彼女自身の原則によって、それが機能する方法に意味があります。
x = 2y-4。
数学では、次のようになります。xを2y -4に等しくします。
また、代数でもこれを行います。変数の方程式を解くとき、解く変数を左側に分離します。つまり、y = mx + b;
さらに、Cファミリなどの言語ファミリ全体が特定の構文を持つと、変更にコストがかかります。
BASIC
、最も初期のコンピューター言語の1つは、「適切な」形式でした。
10 LET AREA = HEIGHT * WIDTH
これは、「Hをオブジェクトの高さにする」のように、変数を指定する数学的考え方と一致します。
COBOL
もCOMPUTE
ステートメントと似ていました。物事を行う多くの方法と同様に、それは単に多くの言語を通して引き継がれた恣意的な決定であったかもしれません。
実際には、右側に割り当てるプログラミング言語があります。 TI-BASIC !それだけでなく、代入演算子として「=」を使用せず、「STO」演算子と呼ばれる矢印を使用しています。
例:
5→A
(A + 3)→B
(A - B)→C
上記の例では、3つの変数が宣言され、値が指定されています。 Aは5、Bは8、Cは-3になります。最初の宣言/割り当ては「store 5 as A」と読むことができます。
なぜTI-BASICがこのようなシステムを割り当てに使用するのかについては、それが電卓のプログラミング言語であることに起因すると考えています。 TI電卓の「STO」演算子は、通常の電卓操作で最も頻繁に使用されましたafter数値が計算されました。ユーザーが覚えておきたい数字の場合、「STO」ボタンを押すと、名前を入力するように求められます(自動的にアルファロックがかかり、キーストロークで数字ではなく文字が生成されます)。
Sin(7 + Cos(3))
-.26979276
Ans→{variable name}
-.26979276
また、ユーザーは変数に任意の名前を付けることができます。アルファロックをオンにし、名前を入力してから、「STO」を押し、「Ans」キーを押すのは、通常の操作では非常に面倒でした。すべての電卓機能はTI-BASICで使用できるため、他のほとんどの言語と比較すると「STO」が同じタスクを実行するため、他の代入演算子は追加されていません。
(付属文書:TI-BASICは私が最初に学んだ言語の1つだったので、私が最初に学んだときJava大学でJavaを割り当てるのは普通ではなく、「後方」であるかのように感じました! )
ヒューリスティック1:言語の設計中に何かを行うための複数の可能な方法に直面した場合、最も一般的で最も直感的な方法を選択しないと、最終的にはPerl +を使用する
今、(少なくとも英語を話す人にとって)それはどのように自然ですか?英語でどのように書く/言うかを見てみましょう:
スティーブンは現在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++で役立つかもしれませんが、ほとんどの人が同意するはずです。コンパイラーが重労働を行い、ヨーダ条件の必要性を軽減できれば、人生は少し楽になります。
もちろん、何にでも慣れることができます。たとえば、81は次のように記述されます。
Eighty One(English)Eighty and one(Spanish)One and Eighty(German).
最後に、4つあります! =ロシア語で「緑Apple lies on table)」と言う24の有効な方法-'on'は 'table'と一緒でなければならないことを除いて、順序は(ほとんど)重要ではありません。あなたは(例えば)ロシア語を母国語とする人なら、a = 10
または10 = a
どちらも同じように自然に見えるため。
言語学は魅力的な主題ですが、私はそれを正式に研究したことはなく、多くの言語を知りません。うまくいけば、私は十分な反例を提供しました。
それは1950年代にFORTRANで始まりました。ここで、FORTRANはFORmula TRANslationの略称でした。問題の数式は、慣例により常に左側に割り当てられる単純な代数方程式です。
一方、そのほぼ現代的なCOBOLは、英語のようなものであり、右側に割り当てられていました(主に!)。
MOVE 1 TO COUNTER.
ADD +1 TO LINE-CNT.
MULTIPLY QTY BY PRICE GIVING ITEM-PRICE.
まあ、@ diceguyd30が指摘したように、両方の表記法があります。
<Identifier> = <Value>
は、「let Identifier be Value "」を意味します。またはそれを拡張するには:変数IdentifierをValueに定義(または再定義)します。<Value> -> <Identifier>
は、「store Value to Identifier "を意味します。またはそれを拡張するには:ValueをIdentifierで指定された場所に配置します。もちろん、一般的に言えばIdentifierは実際にはどのようなL値でもかまいません。
最初のアプローチは変数の抽象的な概念を尊重し、2番目のアプローチは実際のストレージに関するものです。
最初のアプローチは、割り当てがない言語でも一般的です。また、変数の定義と割り当ては比較的近い<Type> <Identifier> = <Value>
対<Identifier> = <Value>
。
これは、初期の解析アルゴリズムの残骸である可能性があります。 LR構文解析は1965年に発明されただけであり、LLパーサーが(当時のマシンの時間とスペースの制限内で)逆の問題を抱えていた可能性があります。検討してください:
identifier = function();
function();
2つは、2番目のトークンから明確に区別されます。一方、
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
パンチできない場合は、必要な識別子を見つけるのがはるかに難しくなります。
すでに述べたように、初期のコンピュータ言語はすべてそのように機能しました。例えば。 BASICの何年も前に登場したFORTRAN。
割り当てられた変数を割り当て式の左側に置くことは、実際には非常に理にかなっています。一部の言語では、同じ名前のオーバーロードルーチンがいくつかあり、異なるタイプの結果を返す場合があります。コンパイラーに割り当てられた変数のタイプを最初に確認させることにより、呼び出すオーバーロードされたルーチン、または整数から浮動小数点数に変換するときに(たとえば)生成する暗黙のキャストがわかります。それは少し単純化した説明ですが、うまくいけば、あなたはアイデアを理解するでしょう。
価値があるのは、COBOLのほとんどのステートメントが左から右に読み取られるため、2つのオペランドが最初に指定され、宛先が最後に名前が付けられる(例:multiply salary by rate giving tax
)。
ただし、私は、このような低くて無礼で味のないコメントをしたことで私が(かなり正しく)フラグを立てられることを恐れて、COBOLを好むかもしれないと提案しません! :-)
彼女は、左から右に向かって自然に見えるようになりました。なぜなら、それが私たちのほとんどが自然言語を読む方法だからです。
これは間違いだと思います。一方では、「10をxに割り当てる」または「10をxに移動する」と言うことができます。一方、「xを10に設定」または「xが10になる」と言うことができます。
つまり、動詞の選択に応じて、割り当て先変数が主語である場合とそうでない場合があり、左側にある場合とない場合があります。したがって、「自然なこと」は、割り当てを表すための習慣的な言い回しの選択に完全に依存します。
擬似コードでは、代入演算子は非常に一般的に右側に記述されます。例えば
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://en.wikipedia.org/wiki/Assignment_%28computer_science%29#Notation
ほとんどの言語では、値を左側に割り当てます。その理由の1つは、演算子の位置合わせが簡単で、変数の読み取りと認識が容易です。これは、割り当て演算子と変数の位置が行内で大きく変わることがなく、次のように読みやすいためです。 「変数を何らかの値にする」。
ただし、「値xをyに移動する」と言い、右側に変数を書き込む人もいます。