私はc#について尋ねていますが、他のほとんどの言語でも同じだと思います。
誰かが表現とステートメントの良い定義を持っていますか、そしてその違いは何ですか?
私はc#について尋ねていますが、他のほとんどの言語でも同じだと思います。
誰かが表現とステートメントの良い定義を持っていますか、そしてその違いは何ですか?
回答:
式:値に評価されるもの。例:1 + 2 / x
ステートメント:何かを行うコード行。例:GOTO 100
FORTRANのような初期の汎用プログラミング言語では、その区別は非常に明確でした。FORTRANでは、ステートメントは実行の1単位でした。「ライン」と呼ばれなかった唯一の理由は、複数のラインにまたがることがあったためです。式だけでは何もできません...変数に割り当てる必要がありました。
1 + 2 / X
それは何もしないので、FORTRANのエラーです。あなたはその表現で何かをしなければなりませんでした:
X = 1 + 2 / X
FORTRANには、私たちが今日知っているような文法はありませんでした。その考えは、Algol-60の定義の一部としてバッカスナウアフォーム(BNF)とともに考案されました。その時点で、セマンティックの違い(「値を持っている」と「何かをする」)が構文に安置されていました。ある種類のフレーズは式であり、別のフレーズはステートメントであり、パーサーはそれらを区別できました。
後の言語の設計者は、区別をあいまいにしました。構文式が物事を行うことを許可し、値を持つ構文ステートメントを許可しました。まだ生き残っている最も初期の人気のある言語の例はCです。Cの設計者は、式を評価して結果を破棄することが許可されていれば害はないことに気付きました。Cでは、末尾にセミコロンを付けるだけで、すべての構文式をステートメントにすることができます。
1 + 2 / x;
絶対に何も起こりませんが、完全に合法的な声明です。同様に、Cでは、式に副作用があり、何かを変更する可能性があります。
1 + 2 / callfunc(12);
callfunc
何か便利なことがあるからです。
式をステートメントにすることを許可したら、式内で代入演算子(=)を許可することもできます。そのため、Cでは次のようなことができます。
callfunc(x = 2);
これは、式x = 2(2の値をxに割り当てる)を評価し、それ(2)を関数に渡しますcallfunc
。
この式とステートメントのぼかしは、すべてのC派生(C、C ++、C#、およびJava)で発生します。これらにはまだいくつかのステートメント(などwhile
)がありますが、ほとんどすべての式をステートメントとして使用できます(C#のみの割り当てでは、 call、increment、およびdecrement式はステートメントとして使用できます。ScottWisniewskiの回答を参照してください)。
2つの「構文カテゴリ」(これは、モノのステートメントと式の一種の技術名です)があると、作業が重複する可能性があります。たとえば、Cには2つの形式の条件があります。ステートメント形式
if (E) S1; else S2;
そして表現形式
E ? E1 : E2
そして、時には人々が望んがない重複を標準Cには、例えば、唯一のステートメントは、宣言することができ、新たなローカル変数-が、この能力は、GNU Cコンパイラを宣言するために発現を可能にGNUの拡張機能を提供することを便利に十分ですローカル変数も同様です。
他の言語の設計者はこの種の複製を好まなかったため、式に副作用だけでなく値も含まれる可能性がある場合、ステートメントと式の間の構文上の区別はそれほど有用ではないので、それを排除しました。 。Haskell、Icon、Lisp、およびMLはすべて、構文ステートメントを持たない言語であり、式しかありません。クラス構造のループと条件付きフォームも式と見なされ、それらには値がありますが、あまり興味深いものではありません。
callfunc(x = 2);
渡さx
れます。がfloatの場合、ではなく呼び出されます。あなたが渡した場合やC ++で、へ、および参照を取り、それを変更し、それが変化し、ではありません。callfunc
2
x
callfunc(float)
callfunc(int)
x=y
func
func
x
y
where
haskellの節がステートメントではなく式と見なされる理由を知りたいです。 learnyouahaskell.com/syntax-in-functions#where
where
は実際には式やステートメントではなく、関数宣言の一部だと思います。
Cでは、「=」は実際には演算子であり、次の2つのことを行うことに注意してください。
ANSI C文法からの抜粋です。Cにはさまざまな種類のステートメントがないことがわかります。プログラムのステートメントの大部分は式ステートメントです。つまり、最後にセミコロンが付いた式です。
statement
: labeled_statement
| compound_statement
| expression_statement
| selection_statement
| iteration_statement
| jump_statement
;
expression_statement
: ';'
| expression ';'
;
式は値を返すものですが、ステートメントは返しません。
例えば:
1 + 2 * 4 * foo.bar() //Expression
foo.voidFunc(1); //Statement
2つの間の大きな問題は、式をチェーン化できるのに対し、ステートメントはチェーン化できないことです。
foo.voidFunc(1);
void値を持つ式です。while
とif
ステートメントです。
return
見なされていると思います。
式とステートメントの構成可能性(連鎖可能性)の重要な違いの説明については、John Backusのチューリング賞の論文「プログラミングをフォンノイマンスタイルから解放できるか?」。
命令型言語(Fortran、C、Javaなど)は、プログラムを構造化するためのステートメントを強調し、ある種の後付けとして式を持っています。関数型言語は式を強調します。 純粋な関数型言語には、ステートメントを完全に排除できるほど強力な式があります。
式は値を取得するために評価できますが、ステートメントは値を返しません(型はvoidです)。
関数呼び出し式もステートメントと見なすことができますが、実行環境に戻り値を保持するための特別な組み込み変数がない限り、それを取得する方法はありません。
ステートメント指向言語では、すべてのプロシージャがステートメントのリストである必要があります。おそらくすべて関数型言語である式指向言語は、式のリスト、またはLISPの場合は、式のリストを表す1つの長いS式です。
両方のタイプを構成できますが、タイプが一致する限り、ほとんどの式を任意に構成できます。ステートメントのタイプごとに、他のステートメントを作成する独自の方法があります(可能な場合)。foreachおよびifステートメントは、単一のステートメントを必要とするか、サブステートメントで独自のサブステートメントが許可されていない限り、すべての従属ステートメントが1つずつステートメントブロックに入るようにします。
ステートメントには式を含めることもできますが、式には実際にはステートメントが含まれません。ただし、1つの例外は、関数を表すラムダ式であり、Pythonの単一式ラムダのように、言語で制限されたラムダのみが許可されている場合を除き、関数に含めることができるすべてのものを含めることができます。
式ベースの言語では、すべての制御構造が値を返すため(それらの多くはNILを返すため)、必要なのは関数の単一の式だけです。関数で最後に評価された式が戻り値なので、returnステートメントは必要ありません。
null
)?ユニットタイプのvoid
ようなものではありませんか(ただし、単一の値にはアクセスできません)。
void
決して戻って(例えば関数という関数の戻り値の型であるthrow
エラーをS)、それはボトム型。それ以外の場合void
は、ユニットタイプです。あなたは発散できないステートメントがユニットタイプを持っていることは正しいです。しかし、発散する可能性のあるステートメントは一番下のタイプです。停止定理のため、通常、関数が発散しないことを証明できないため、単位はフィクションだと思います。下部の型は値を持つことができないため、単一の値を持つことはできませんnull
。
null
値が本当にあるpseudovalue参照が存在しない何かを参照していることを示します。
単に:式は値に評価されますが、ステートメントは評価されません。
{}
ステートメントです。単語を怖い引用符で囲んでも、それは変わりません。ステートメントは、セマンティクスを持つ構文構造です。「セマンティクスレイヤー」などというものはありません。あなたは実行について言及しているようです。あなたはあなたが正確にしようとしていると言いますが、あなたはそれで失敗しました。「反対投票者の無知」についてのあなたの不満は純粋なアドホミネムです。反対投票者の精神状態についての情報はありません。
{}
C#言語仕様のステートメントとして定義されています。
式ベースの言語に関するいくつかのこと:
最も重要:すべてが値を返す
すべてが式であるため、コードブロックと式を区切る中括弧と中括弧の間に違いはありません。ただし、これによって字句スコープが妨げられることはありません。たとえば、ローカル変数は、その定義が含まれている式と、その中に含まれているすべてのステートメントに対して定義できます。
式ベースの言語では、すべてが値を返します。これは最初は少し奇妙なことがあります-何をします(FOR i = 1 TO 10 DO (print i))
戻りますか?
いくつかの簡単な例:
(1)
戻り値 1
(1 + 1)
戻り値 2
(1 == 1)
戻り値 TRUE
(1 == 2)
戻り値 FALSE
(IF 1 == 1 THEN 10 ELSE 5)
戻り値 10
(IF 1 == 2 THEN 10 ELSE 5)
戻り値 5
いくつかのより複雑な例:
OpenADoor(), FlushTheToilet()
またはTwiddleYourThumbs()
を呼び出す と、OK、Done、Successなどのありふれた値が返されます。(FOR i = 1 TO 10 DO (print i))
は、forループの値は "10"であり、(print i)
式が10回評価され、そのたびにiが文字列として返されます。リターンの最後の時間10
、私たちの最後の答えすべてが式であるという事実により、多くのことを「インライン化」できるため、式ベースの言語を最大限に活用するために、考え方のわずかな変更が必要になることがよくあります。
簡単な例として:
FOR i = 1 to (IF MyString == "Hello, World!" THEN 10 ELSE 5) DO ( LotsOfCode )
非表現ベースの完全に有効な置き換えです
IF MyString == "Hello, World!" THEN TempVar = 10 ELSE TempVar = 5 FOR i = 1 TO TempVar DO ( LotsOfCode )
場合によっては、式ベースのコードで許可されているレイアウトが私にとってはるかに自然に感じる
もちろん、これは狂気につながる可能性があります。MaxScriptと呼ばれる式ベースのスクリプト言語での趣味のプロジェクトの一環として、なんとかこのモンスターラインを思いついた
IF FindSectionStart "rigidifiers" != 0 THEN FOR i = 1 TO (local rigidifier_array = (FOR i = (local NodeStart = FindsectionStart "rigidifiers" + 1) TO (FindSectionEnd(NodeStart) - 1) collect full_array[i])).count DO
(
LotsOfCode
)
ステートメントは式の特殊なケースであり、 void
タイプを式の。言語がステートメントを異なる方法で処理する傾向はしばしば問題を引き起こし、それらが適切に一般化されればより良いでしょう。
たとえば、C#には、非常に便利なFunc<T1, T2, T3, TResult>
オーバーロードされたジェネリックデリゲートのセットがあります。しかし、対応するAction<T1, T2, T3>
セットも必要です。この不幸な分岐に対処するには、汎用の高次プログラミングを常に複製する必要があります。
簡単な例-別の関数を呼び出す前に参照がnullかどうかをチェックする関数:
TResult IfNotNull<TValue, TResult>(TValue value, Func<TValue, TResult> func)
where TValue : class
{
return (value == null) ? default(TValue) : func(value);
}
コンパイラはTResult
存在する可能性を処理できvoid
ますか?はい。それがしなければならないことは、returnの後にtypeの式が続くことを要求することだけですvoid
。の結果はdefault(void)
型void
であり、渡されるfuncはFunc<TValue, void>
(と同等のAction<TValue>
)形式である必要があります。
他の多くの答えは、式のようにステートメントを連鎖できないことを意味しますが、この考えがどこから来たのかはわかりません。;
ステートメントの後に現れるは、2つの中置演算子と考えることができます。型の2つの式を取りvoid
、それらをtypeの1つの式に結合しますvoid
。
ステートメント->順次実行する指示
式->値を返す評価
ステートメントは基本的にはステップやアルゴリズムの命令に似ており、ステートメントの実行結果は命令ポインターの実現(いわゆるアセンブラー)です。
式は暗黙的に実行順序を示すものではなく、その目的は値を評価して返すことです。命令型プログラミング言語では、式の評価には順序がありますが、それは命令型モデルのせいだけですが、それらの本質ではありません。
ステートメントの例:
for
goto
return
if
(それらはすべて、実行の行(ステートメント)が別の行に進むことを意味します)
式の例:
2+2
(それは実行の考えを意味するのではなく、評価の意味を意味します)
ステートメントは、すべてのC#プログラムが構築される手続き型のビルディングブロックです。ステートメントは、ローカル変数または定数の宣言、メソッドの呼び出し、オブジェクトの作成、または変数、プロパティ、フィールドへの値の割り当てを行うことができます。
中括弧で囲まれた一連のステートメントは、コードのブロックを形成します。メソッド本体は、コードブロックの一例です。
bool IsPositive(int number)
{
if (number > 0)
{
return true;
}
else
{
return false;
}
}
C#のステートメントには、多くの場合、式が含まれています。C#の式は、リテラル値、単純な名前、または演算子とそのオペランドを含むコードのフラグメントです。
式、
式は、単一の値、オブジェクト、メソッド、または名前空間に評価できるコードのフラグメントです。最も単純な2つのタイプの式は、リテラルと単純な名前です。リテラルは名前のない定数値です。
int i = 5;
string s = "Hello World";
iとsはどちらも、ローカル変数を識別する単純な名前です。これらの変数が式で使用されると、変数の値が取得され、式に使用されます。
if(number >= 0) return true; else return false;
かもっと上手くいきたいですbool? IsPositive(int number) { if(number > 0) return true; else if(number < 0) return false; else return null;}
:)
私はここの答えのどれにも本当に満足していません。C ++(ISO 2008)の文法を見た。しかし、おそらく教授法とプログラミングのために、2つの要素を区別するには答えで十分かもしれません(ただし、現実はもっと複雑に見えます)。
ステートメントは0個以上の式で構成されますが、他の言語の概念にすることもできます。これは、文法の拡張バッカスナウアフォームです(ステートメントの抜粋):
statement:
labeled-statement
expression-statement <-- can be zero or more expressions
compound-statement
selection-statement
iteration-statement
jump-statement
declaration-statement
try-block
C ++のステートメントと見なされる他の概念を見ることができます。
case
たとえば、ラベル付きステートメントですif
if/else
、case
while
、do...while
、for (...)
break
、continue
、return
、(式を返すことができます)goto
try/catch
ですこれは、式の部分を示す抜粋です。
expression:
assignment-expression
expression "," assignment-expression
assignment-expression:
conditional-expression
logical-or-expression assignment-operator initializer-clause
throw-expression
+
、-
、*
、/
、&
、|
、&&
、||
、...)throw
句はあまりにも表現です文は文法的に完全な文です。式はそうではありません。例えば
x = 5
「xは5を取得します」と読み取ります。これは完全な文です。コード
(x + 5)/9.0
「xプラス5すべてを9.0で割った値」と読み取ります。これは完全な文ではありません。ステートメント
while k < 10:
print k
k += 1
完全な文です。ループヘッダーはそうではないことに注意してください。「while k <10」は従属節です。
while
ボディ付きのA は、Scalaではまだ式です。それが副作用を生み出す場合、それは声明でもあるかもしれません。これは、私の反対投票の答えが許すものです(式は声明でもかまいません)。私の答えは唯一正しいものです。理解できない読者の皆さん、ごめんなさい。
(x + 5)/9.0
、ステートメントとして間違いなく独立できます。また、文法的に完全な場合は、有効なプログラムを意味します。Cでは、ステートメントを単一のプログラムとして独立させることはできません。
これが、私が見つけた最も簡単な答えの1つです。
Anders Kaseorgが最初に回答
ステートメントは、何らかのアクションを実行するコードの完全な行であり、式は、値に評価されるコードの任意のセクションです。
式は、演算子を使用して「水平に」より大きな式に組み合わせることができますが、ステートメントを「垂直に」組み合わせることができるのは、次々に記述するか、ブロック構成でのみです。
すべての式はステートメントとして使用できます(その効果は式を評価し、結果の値を無視することです)が、ほとんどのステートメントは式として使用できません。
これらの概念の事実上の基礎は次のとおりです。
式:インスタンスを値に評価できる構文カテゴリ。
ステートメント:そのインスタンスが式の評価に関与する可能性のある構文カテゴリと、評価の結果の値(存在する場合)は、利用できることが保証されていません。
何十年も前のFORTRANのごく初期の状況に加えて、受け入れられた回答の表現とステートメントの両方の定義は明らかに間違っています。
sizeof
は評価されません。(ところで、DMRにそのような意見があるかどうか思い出せないので、Cに関する資料に関するその回答に[引用が必要]を追加したいと思います。そうではないようです。そうでなければ、Cの設計で機能の重複を保持する理由はないはずです:特に、ステートメントに対するコンマ演算子。)
(以下の根拠は元の質問に対する直接の回答ではありませんが、ここですでに回答されていることを明確にする必要があると思います。)
それにもかかわらず、汎用プログラミング言語で特定のカテゴリの「ステートメント」が必要かどうかは疑問です。
begin
Schemeなど)またはモナディック構造の構文糖に置き換えることができます。++i + ++i
Cで意味のないポイントを取得する方法を検討してください。)なぜ声明なのか?とにかく、歴史はすでに混乱しています。ほとんどの言語デザイナーは慎重に選択をしていません。
さらに悪いことには、型システムの愛好家(PLの歴史に十分に精通していない)にも、型システムは運用上のセマンティクスに関するより重要なルールの設計に重要なことをしなければならないという誤解を与えることさえあります。
真剣に、タイプに依存する推論は多くの場合それほど悪くありませんが、この特別なケースでは特に建設的ではありません。専門家でさえ物事を台無しにすることができる。
たとえば、区切り文字なしの継続の従来の扱いに対する反対の中心的な議論として、タイピングの性質を強調する人がいます。結論はやや妥当であり、合成された関数に関する洞察はOKですが(本質的にはあまりにも単純すぎる)、この引数は実際には_Noreturn any_of_returnable_types
(サイドチャネル)アプローチを無視して(C11のように)エンコードするため、適切ではありませんFalsum
。 厳密に言えば、予測不可能な状態の抽象的なマシンは「クラッシュしたコンピュータ」と同じではありません。
ステートメント指向プログラミング言語では、コードブロックはステートメントのリストとして定義されます。つまり、ステートメントは、構文エラーを発生させることなくコードブロック内に配置できる構文の一部です。
ウィキペディアは同様に単語ステートメントを定義しています
コンピュータプログラミングでは、ステートメントは、実行するアクションを表現する命令型プログラミング言語の構文単位です。そのような言語で書かれたプログラムは、一連の1つ以上のステートメントによって形成されます
後者のステートメントに注意してください。(この場合の「プログラム」は技術的に間違っていますが、CとJavaの両方がステートメントだけで構成されるプログラムを拒否するためです。)
ウィキペディアは単語表現を次のように定義しています
プログラミング言語の式は、その値を決定するために評価できる構文エンティティです
ただし、これはfalseです。Kotlinではthrow new Exception("")
式ですが、評価されると例外をスローするだけで、値を返しません。
静的に型付けされたプログラミング言語では、すべての式に型があります。ただし、この定義は動的に型付けされたプログラミング言語では機能しません。
個人的には、式を、演算子または関数呼び出しで構成してより大きな式を生成できる構文の一部として定義しています。これは実際にはウィキペディアによる表現の説明に似ています:
これは、1つ以上の定数、変数、関数、および演算子の組み合わせであり、プログラミング言語が(優先順位と関連付けの特定の規則に従って)解釈し、別の値を生成する(ステートフル環境で「返す」)ように計算します。
しかし、問題は、次のような関数executeSomethingを与えられたCプログラミング言語にあります:
void executeSomething(void){
return;
}
executeSomething()
式ですか、それともステートメントですか?私の定義によると、これはステートメントです。MicrosoftのC参照文法で定義されているように、
void型の式の(存在しない)値を使用することはできません。また、void式を(暗黙的または明示的な変換によって)void以外の型に変換することもできません。
しかし、同じページは、そのような構文が式であることを明確に示しています。
私の以前の答えを改善して検証するには、プログラミング言語の用語の定義を、該当する場合はコンピューターサイエンスの型理論から説明する必要があります。
式にBottomタイプ以外のタイプがあります。つまり、式に値があります。ステートメントにはUnitまたはBottomタイプがあります。
このことから、ステートメントは、副作用を作成するときにプログラムでのみ効果を持つことができます。これは、値を返すことができないか、割り当て不可であるUnitタイプの値のみを返すためです(一部の言語など)。 Cのvoid
)または(Scalaの場合など)は、ステートメントの遅延評価のために格納できます。
明らかにa @pragma
またはaに/*comment*/
は型がないため、ステートメントと区別されます。したがって、副作用のない唯一のタイプのステートメントは、非演算になります。非操作は、将来の副作用のプレースホルダーとしてのみ役立ちます。ステートメントに起因するその他のアクションは、副作用となります。繰り返しになりますが、たとえば@pragma
、型がないため、コンパイラヒントはステートメントではありません。
@pragma
または/*comment*/
論理的に一貫性がありません。
最も正確には、ステートメントが持っている必要があり、「副作用」(すなわちことが不可欠に)と式はしなければならない持っている値の種類(すなわちないボトム型)を。
ステートメントのタイプは単位タイプですが、定理の停止により単位はフィクションなので、ボトムタイプと言いましょう。
Void
正確には最下部のタイプではありません(すべての可能なタイプのサブタイプではありません)。それは完全に健全な型システムを持っていない言語で存在します。これは気の利いた発言のように聞こえるかもしれませんが、分散アノテーションなどの完全性は、拡張可能なソフトウェアを書くために重要です。
この件に関してウィキペディアが何を言わなければならないか見てみましょう。
https://en.wikipedia.org/wiki/Statement_(computer_science)
コンピュータプログラミングでは、ステートメントは、実行されるいくつかのアクションを表す命令型プログラミング言語の最小のスタンドアロン要素です。
多くの言語(Cなど)はステートメントと定義を区別し、ステートメントは実行可能コードと識別子を宣言する定義のみを含み、式は値のみを評価します。
pass
ではステートメントです。これはノーオペレーションであり、何にも評価されません。