Я спрашиваю относительно c #, но я предполагаю, что то же самое в большинстве других языков.
У кого-нибудь есть хорошее определение выражений и утверждений и в чем различия?
Я спрашиваю относительно c #, но я предполагаю, что то же самое в большинстве других языков.
У кого-нибудь есть хорошее определение выражений и утверждений и в чем различия?
Ответы:
Выражение: что-то, что оценивает значение. Пример: 1 + 2 / x
Заявление: строка кода, которая что-то делает. Пример: GOTO 100
В самых ранних языках программирования общего назначения, таких как FORTRAN, различие было кристально ясным. В FORTRAN оператор был одной единицей исполнения, то, что вы сделали. Единственная причина, по которой его не называли «линией», заключалась в том, что иногда он занимал несколько строк. Выражение само по себе ничего не может сделать ... вы должны были присвоить его переменной.
1 + 2 / X
это ошибка в Фортране, потому что она ничего не делает. Вы должны были что-то сделать с этим выражением:
X = 1 + 2 / X
У Фортрана не было грамматики в том виде, в каком мы ее знаем сегодня - эта идея была изобретена вместе с формой Бэкуса-Наура (БНФ), как часть определения Алгол-60. В этот момент семантическое различие («иметь значение» и «делать что-то») было закреплено в синтаксисе : один вид фразы был выражением, а другой - утверждением, и синтаксический анализатор мог их различать.
Разработчики более поздних языков размыли различие: они позволяли синтаксическим выражениям делать что-то, и они допускали синтаксические выражения, которые имели значения. Самый ранний популярный пример языка, который до сих пор сохранился, - C. Разработчики C поняли, что никакого вреда не было, если вам позволили оценить выражение и выбросить результат. В C каждое синтаксическое выражение может быть преобразовано в утверждение, просто ставя точку с запятой в конце:
1 + 2 / x;
это абсолютно законное заявление, хотя абсолютно ничего не произойдет. Точно так же в C выражение может иметь побочные эффекты - оно может что-то изменить.
1 + 2 / callfunc(12);
потому что callfunc
может просто сделать что-то полезное.
Как только вы позволите любому выражению быть оператором, вы также можете разрешить оператор присваивания (=) внутри выражений. Вот почему С позволяет вам делать такие вещи, как
callfunc(x = 2);
Это вычисляет выражение x = 2 (присваивая значение от 2 до x) и затем передает это (2) в функцию callfunc
.
Это размывание выражений и операторов происходит во всех C-производных (C, C ++, C # и Java), которые все еще имеют некоторые операторы (например while
), но которые позволяют использовать практически любое выражение в качестве оператора (в присваивании только C #, Выражения вызова, приращения и декремента могут использоваться в качестве операторов (см . ответ Скотта Вишневского ).
Наличие двух «синтаксических категорий» (так называемых технических терминов для выражений и выражений) может привести к дублированию усилий. Например, C имеет две формы условного выражения:
if (E) S1; else S2;
и форма выражения
E ? E1 : E2
И иногда люди хотят дублирования, которого нет: например, в стандартном C только оператор может объявить новую локальную переменную, но эта возможность достаточно полезна, так как компилятор GNU C предоставляет расширение GNU, которое позволяет выражению объявлять локальная переменная также.
Проектировщикам других языков не понравился такой тип дублирования, и они рано поняли, что если выражения могут иметь побочные эффекты, а также значения, то синтаксическое различие между утверждениями и выражениями не так уж и полезно, поэтому они избавились от него. , Haskell, Icon, Lisp и ML - все языки, которые не имеют синтаксических операторов - они имеют только выражения. Даже структурированные циклы класса и условные формы считаются выражениями, и они имеют значения, но не очень интересные.
callfunc(x = 2);
переходит x
на callfunc
нет 2
. Если x
это поплавок, callfunc(float)
будет называться, а не callfunc(int)
. И в C ++, если вы передаете x=y
к func
и func
принимает ссылку и изменяет его, она меняется x
, не y
.
where
предложение в haskell считается выражением, а не утверждением. learnyouahaskell.com/syntax-in-functions#where
where
что на самом деле это часть объявления функции, а не выражение или утверждение.
Обратите внимание, что в C "=" на самом деле является оператором, который выполняет две вещи:
Вот выдержка из грамматики 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
Большая сделка между ними состоит в том, что вы можете связывать выражения вместе, тогда как операторы не могут быть связаны.
foo.voidFunc(1);
является выражением со значением void. while
и if
являются заявлениями.
return
считается подзаголовком.
Вы можете найти это в википедии , но выражения оцениваются до некоторого значения, в то время как операторы не имеют оцененного значения.
Таким образом, выражения могут использоваться в выражениях, но не наоборот.
Обратите внимание, что некоторые языки (такие как Lisp, и, я полагаю, Ruby и многие другие) не различают оператор и выражение ... в таких языках все является выражением и может быть связано с другими выражениями.
Для объяснения важных различий в сочетаемости (цепочечности) выражений и выражений моя любимая ссылка - дипломная работа Тьюринга Джона Бэкуса: Можно ли освободить программирование от стиля фон Неймана? ,
В императивных языках (Fortran, C, Java, ...) подчеркиваются операторы для структурирования программ, а выражения являются своего рода запоздалым размышлением. Функциональные языки подчеркивают выражения. Чисто функциональные языки имеют такие мощные выражения, что операторы могут быть полностью исключены.
Выражения могут быть оценены, чтобы получить значение, тогда как операторы не возвращают значение (они имеют тип void ).
Выражения вызова функций также можно рассматривать как операторы, но, если в среде выполнения нет специальной встроенной переменной для хранения возвращаемого значения, его невозможно получить.
Языки, ориентированные на операторы, требуют, чтобы все процедуры были списком операторов. Ориентированные на выражения языки, которые, вероятно, являются всеми функциональными языками, представляют собой списки выражений или, в случае LISP, одно длинное S-выражение, представляющее список выражений.
Хотя оба типа могут быть составлены, большинство выражений может быть составлено произвольно, если типы совпадают. Каждый тип оператора имеет свой собственный способ составления других операторов, если они могут делать все это. Foreach и, если для операторов требуется либо одна инструкция, либо чтобы все подчиненные операторы помещались в блоке операторов один за другим, если только подзаголовки не позволяют использовать их собственные подзаголовки.
Выражения могут также включать выражения, где выражение на самом деле не содержит никаких утверждений. Однако одним исключением может быть лямбда-выражение, которое представляет функцию, и поэтому может включать в себя все, что функция может исключить, если язык не допускает только ограниченные лямбды, такие как лямбды Python с одним выражением.
В языке на основе выражений все, что вам нужно, - это одно выражение для функции, поскольку все управляющие структуры возвращают значение (многие из них возвращают NIL). Нет необходимости в операторе возврата, так как последнее вычисленное выражение в функции является возвращаемым значением.
Void
это не нижний тип. Смотри мой ответ .
null
)? Не будет void
ли больше похож на тип устройства (но с единственным недоступным значением)?
void
это тип возврата функции, которая никогда не возвращается (например, функция, которая throw
является ошибкой), это тип снизу . В противном случае void
это тип устройства . Вы правы, что утверждение, которое не может расходиться, имеет тип единицы измерения. Но утверждение, которое может расходиться, является типом дна. Из-за теоремы Остановки мы обычно не можем доказать, что функция не расходится, поэтому я думаю, что единица - это выдумка. Нижний тип не может иметь значения, поэтому он не может иметь единственного значения null
.
null
Значение действительно pseudovalue обозначая , что ссылка указывает на то , что не существует.
Просто: выражение оценивается как значение, а выражение - нет.
{}
это утверждение. Помещение слова в кавычки не меняет этого. Заявления являются синтаксическими конструкциями с семантикой. Нет такого понятия, как «уровень семантики» - вы, похоже, имеете в виду выполнение . Вы говорите, что пытаетесь быть точным, но у вас ничего не получилось. Ваша жалоба о "невежестве недовольных избирателей" - это чистый ad hominem; у вас нет информации о психических состояниях downvoters.
{}
определяется как оператор в спецификации языка 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, Готово или Успех.(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>
набор, и постоянно нужно дублировать программирование более высокого порядка общего назначения, чтобы справиться с этой печальной бифуркацией.
Тривиальный пример - функция, которая проверяет, является ли ссылка нулевой, перед вызовом другой функции:
TResult IfNotNull<TValue, TResult>(TValue value, Func<TValue, TResult> func)
where TValue : class
{
return (value == null) ? default(TValue) : func(value);
}
Может ли компилятор иметь дело с возможностью TResult
существования void
? Да. Все, что нужно сделать, это потребовать, чтобы за возвращением следовало выражение, имеющее тип void
. Результат default(void)
будет иметь тип void
, и передаваемая функция должна иметь форму Func<TValue, void>
(которая будет эквивалентна Action<TValue>
).
Ряд других ответов подразумевает, что вы не можете связать утверждения, как вы можете с выражениями, но я не уверен, откуда эта идея. Мы можем думать о том, ;
что появляется после операторов, как бинарный инфиксный оператор, беря два выражения типа void
и объединяя их в одно выражение типа void
.
Заявления -> Инструкции для последовательного следования
выражений -> Оценка, которая возвращает значение
Утверждения в основном похожи на шаги или инструкции в алгоритме, результатом выполнения оператора является актуализация указателя инструкции (так называемого в ассемблере)
Выражения не подразумевают и порядок исполнения с первого взгляда, их цель - оценить и вернуть значение. В императивных языках программирования оценка выражения имеет порядок, но это только из-за императивной модели, но не в их сущности.
Примеры заявлений:
for
goto
return
if
(все они подразумевают переход строки (оператора) выполнения к другой строке)
Пример выражения:
2+2
(это подразумевает не идею исполнения, а оценку)
Оператор - это процедурный строительный блок, из которого создаются все программы на C #. Оператор может объявить локальную переменную или константу, вызвать метод, создать объект или присвоить значение переменной, свойству или полю.
Ряд операторов, заключенных в фигурные скобки, образуют блок кода. Тело метода является одним из примеров блока кода.
bool IsPositive(int number)
{
if (number > 0)
{
return true;
}
else
{
return false;
}
}
Выражения в C # часто содержат выражения. Выражение в C # - это фрагмент кода, содержащий буквальное значение, простое имя или оператор и его операнды.
Выражение - это фрагмент кода, который может быть оценен для одного значения, объекта, метода или пространства имен. Два самых простых типа выражений - литералы и простые имена. Литерал - это постоянное значение, которое не имеет имени.
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;}
:)
Я предпочитаю значение statement
в формально-логическом смысле этого слова. Это та, которая изменяет состояние одной или нескольких переменных в вычислениях, позволяя сделать истинное или ложное утверждение об их значениях.
Я предполагаю, что всегда будет путаница в вычислительном мире и науке в целом, когда вводится новая терминология или слова, существующие слова «перепрофилируются» или пользователи не знают о существующей, установленной или «правильной» терминологии в отношении того, что они описывают.
Я не очень удовлетворен ни одним из ответов здесь. Я посмотрел на грамматику для C ++ (ISO 2008) . Однако, возможно, ради дидактики и программирования ответов может быть достаточно, чтобы различить два элемента (хотя реальность выглядит более сложной).
Оператор состоит из нуля или более выражений, но также может представлять собой другие языковые концепции. Это расширенная форма Backus Naur для грамматики (отрывок для утверждения):
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
читается как "х получает 5" Это полное предложение. Код
(x + 5)/9.0
гласит: «х плюс 5 все делится на 9,0». Это не полное предложение. Заявление
while k < 10:
print k
k += 1
это полное предложение. Обратите внимание, что заголовок цикла не является; «в то время как k <10» является подчиненным предложением.
while
Это выражение некоторых языков, таких как Scala. Вы смешиваете грамматику с набором текста. Смотри мой ответ .
while
с телом это еще выражение в Скале. Это также может быть утверждение, если оно создает побочные эффекты, что допускает мой сильно опущенный ответ (выражение также может быть утверждением). Мой ответ - единственный правильный. Извините всех тех читателей, которые не могут понять.
(x + 5)/9.0
безусловно , может стоять в одиночестве как утверждение. Кроме того, если под грамматическим завершением вы подразумеваете допустимую программу, C не позволяет операторам выделяться как отдельная программа.
Вот краткое изложение одного из самых простых ответов, которые я нашел.
Первоначально ответил Андерс Kaseorg
Оператор - это полная строка кода, которая выполняет какое-то действие, а выражение - это любой раздел кода, который оценивает значение.
Выражения могут быть объединены «горизонтально» в более крупные выражения с помощью операторов, тогда как выражения могут быть объединены «вертикально» только путем записи одного за другим или с блочными конструкциями.
Каждое выражение может быть использовано в качестве оператора (результатом которого является оценка выражения и игнорирование полученного значения), но большинство операторов не могут использоваться в качестве выражений.
Де-факто основой этих понятий является:
Выражения : синтаксическая категория, экземпляр которой может быть оценен по значению.
Утверждение : синтаксическая категория, экземпляр которой может быть связан с оценками выражения, и результирующее значение оценки (если есть) не гарантировано доступно.
Помимо самого начального контекста ФОРТРАНА в первые десятилетия, оба определения выражений и утверждений в принятом ответе явно неверны:
sizeof
оператора, никогда не вычисляется.(Кстати, я хочу добавить [цитата нужна] к этому ответу относительно материалов о C, потому что я не могу вспомнить, есть ли у DMR такие мнения. Кажется, нет, в противном случае не должно быть никаких причин сохранять дублирование функциональности в дизайне C : в частности, оператор запятой против операторов.)
(Следующее обоснование не является прямым ответом на первоначальный вопрос, но я считаю необходимым уточнить кое-что, на что здесь уже дан ответ.)
Тем не менее, сомнительно, что нам нужна особая категория «операторов» в языках программирования общего назначения:
begin
на схеме) или синтаксическим сахаром монадных структур.++i + ++i
имеет смысла в C.)Так почему заявления? Во всяком случае, история уже беспорядок. Кажется, большинство языковых дизайнеров не принимают свой выбор тщательно.
Хуже того, он даже дает некоторым энтузиастам систем типов (которые недостаточно знакомы с историей PL) некоторые заблуждения о том, что системы типов должны иметь важные вещи, связанные с более существенными разработками правил операционной семантики.
Серьезно, рассуждение в зависимости от типов не так уж плохо во многих случаях, но особенно неконструктивно в этом особом. Даже эксперты могут все испортить.
Например, кто-то подчеркивает типизирующую природу как центральный аргумент против традиционного подхода к неограниченным продолжениям . Хотя этот вывод несколько обоснован, и понимание составных функций в порядке ( но все же слишком наивно для сути ), этот аргумент не верен, поскольку на практике он полностью игнорирует подход «побочного канала», такой как _Noreturn any_of_returnable_types
(в C11) для кодирования Falsum
. И, строго говоря, абстрактная машина с непредсказуемым состоянием не идентична «разбитому компьютеру».
В языке программирования, ориентированном на операторы, блок кода определяется как список операторов. Другими словами, оператор - это фрагмент синтаксиса, который вы можете поместить в блок кода, не вызывая синтаксической ошибки.
Википедия определяет словосочетание аналогично
В компьютерном программировании оператор - это синтаксическая единица императивного языка программирования, которая выражает некоторые действия, которые необходимо выполнить. Программа, написанная на таком языке, состоит из последовательности одного или нескольких операторов.
Обратите внимание на последнее утверждение. (хотя «программа» в этом случае технически неверна, потому что и C, и Java отклоняют программу, которая не содержит ничего из утверждений.)
Википедия определяет выражение слова как
Выражение в языке программирования - это синтаксическая сущность, которая может быть оценена для определения ее значения.
Это, однако, ложно, потому что в Kotlin throw new Exception("")
это выражение, но при оценке оно просто выдает исключение, никогда не возвращая никакого значения.
В статически типизированном языке программирования каждое выражение имеет тип. Это определение, однако, не работает в динамически типизированном языке программирования.
Лично я определяю выражение как часть синтаксиса, которую можно составить с помощью вызовов оператора или функции, чтобы получить большее выражение. На самом деле это похоже на объяснение выражения в Википедии:
Это комбинация из одной или нескольких констант, переменных, функций и операторов, которую язык программирования интерпретирует (в соответствии со своими конкретными правилами приоритета и ассоциации) и вычисляет для получения («вернуть» в среде с состоянием) другого значения
Но проблема в языке программирования C, учитывая функцию executeSomething следующим образом:
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
есть утверждение. Это неоперация, и это ни к чему не приводит.