Вираз проти твердження


431

Я прошу щодо c #, але я припускаю, що це так само і в більшості інших мов.

Хтось має чітке визначення виразів і висловлювань і в чому відмінності?


4
Я вважаю, що відповідь, яку ви вибрали, є неоднозначною. Вираз також щось робить - він оцінює значення. Я дав неоднозначну відповідь.
Шелбі Мур III

4
@ShelbyMooreIII - Неоднозначне, а також неправильне. Прийнята відповідь формулюється неофіційно, але це формулювання полегшує розуміння - і головне, сенс, який він передає, є точним.
Джастін Морган

@JustinMorgan На жаль, визначення у прийнятій відповіді також очевидно помилкові ("оцінює значення" / "рядок коду") для більшості сучасної мови включають C-подібні: вирази можна використовувати в неоцінених контекстах, а висловлювання не мають нічого робити з лініями. Навіть є деякі пояснення, коротка відповідь є заплутаною та оманливою.
FrankHB

Відповіді:


520

Вираз: Щось, що оцінює значення. Приклад: 1 + 2 / x
заява: рядок коду, який щось робить. Приклад: GOTO 100

У ранніх мовах програмування загального призначення, як FORTRAN, відмінність була кристально чистою. У FORTRAN заява була однією одиницею страти, що ви зробили. Єдина причина, яку його не називали "лінією", це тому, що іноді вона охоплювала кілька рядків. Самовираз не міг нічого зробити ... вам довелося призначити його змінній.

1 + 2 / X

помилка в FORTRAN, оскільки вона нічого не робить. Вам потрібно було щось зробити з цим виразом:

X = 1 + 2 / X

У FORTRAN не було граматики, як ми її знаємо сьогодні - ця ідея була придумана разом із формою Бекус-Наура (BNF), як частина визначення Алгола-60. У цей момент семантичне відмінність ("мати значення" проти "зробити щось") було закріплено в синтаксисі : один вид фрази - це вираз, а інший - висловлювання, і аналізатор міг їх розрізнити.

Дизайнери пізніших мов розмили розрізнення: вони дозволили синтаксичним виразам робити речі, і вони дозволили синтаксичним висловлюванням, які мали значення. Найдавніший приклад популярної мови, який досі зберігається, - це 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 #, вирази виклику, збільшення та декременту можуть використовуватися як заяви; див. відповідь Скотта Вішневського ).

Наявність двох "синтаксичних категорій" (що є технічною назвою для виду речей і виразів) може призвести до дублювання зусиль. Наприклад, С має дві форми умовної форми висловлювання

if (E) S1; else S2;

і форму виразу

E ? E1 : E2

І іноді люди хочуть дублювання, якого там немає: наприклад, у стандартному С, лише оператор може оголосити нову локальну змінну - але ця здатність є достатньо корисною, щоб компілятор GNU C надав розширення GNU, що дозволяє вираження оголосити локальна змінна.

Дизайнерам інших мов не сподобався подібний тип дублювання, і вони рано побачили, що якщо вирази можуть мати як побічні ефекти, так і значення, то синтаксичне розрізнення висловлювань і виразів не все так корисно - тому вони позбулися цього . Haskell, Icon, Lisp та ML - це всі мови, у яких немає синтаксичних висловлювань - вони мають лише вирази. Навіть структуровані циклічні та умовні форми класу вважаються виразами, і вони мають значення, але не дуже цікаві.


9
Якщо я тут не трактую вас неправильно, ви, схоже, стверджуєте, що "(setf (третій foo)" гусак) "- це вираз, а не твердження, тому що це Lisp, який" не має тверджень ", і тому що Лісп більш ніж на десятиліття старший від C, що був "найбільш ранньою популярною мовою для розмивання рядків [між виразами та висловлюваннями]". Чи можете мені пояснити деталі цього?
cjs

2
@Curt Sampson, ти це задавав як окреме запитання?
Келлі С. Французька

5
Якщо я не помиляюся, callfunc(x = 2);переходить xна callfunc, ні 2. Якщо xце поплавок, callfunc(float)буде називатися, не callfunc(int). І в C ++, якщо ви переходите x=yдо funcта берете funcпосилання та змінюєте його, воно змінюється x, а не y.
Габріель

У відповіді вище написано, що "Haskell, ... це всі мови, які не мають синтаксичних висловлювань - вони мають лише вирази". Мені цікаво, чому whereпункт у haskell вважається виразом, а не висловом. learnnyouahaskell.com/syntax-in-functions#where
skgbanga

@skgbanga Я вважаю where, що насправді є частиною декларації функції, а не виразу чи висловлення.
Акангка

22
  • вираз - це все, що дає значення: 2 + 2
  • оператор є одним з основних "блоків" виконання програми.

Зауважте, що в C "=" - це власне оператор, який робить дві речі:

  • повертає значення правої субекспресії правої руки.
  • копіює значення підвыражения правої руки в змінну з лівого боку.

Ось уривок із граматики ANSI C Ви можете бачити, що у C не так багато різних типів висловлювань ... більшість висловлювань у програмі - це висловлення виразів, тобто вираз з крапкою з комою.

statement
    : labeled_statement
    | compound_statement
    | expression_statement
    | selection_statement
    | iteration_statement
    | jump_statement
    ;

expression_statement
    : ';'
    | expression ';'
    ;

http://www.lysator.liu.se/c/ANSI-C-grammar-y.html


2
Неправильна логіка щодо того, що таке твердження. Декларативна програма також може виконуватися, але декларативна програма не має заяв. Заява є і має "побічні ефекти" , тобто є обов'язковою. пор. моя відповідь .
Шелбі Мур III

15

Вираз - це те, що повертає значення, тоді як вислів - ні.

Наприклад:

1 + 2 * 4 * foo.bar()     //Expression
foo.voidFunc(1);          //Statement

Велика угода між двома полягає в тому, що ви можете зв'язувати вирази разом, тоді як заяви не можуть бути ланцюговими.


6
Звичайно, твердження можуть бути прикованими. {stmt1; stmt2; stmt3;} - це ланцюжок, і це також (складне) твердження.
Х'ю Аллен

5
foo.voidFunc(1);- вираз із значенням пустоти. whileі ifє твердженнями.
tzot

Мені цікаво невтручання тверджень. Буде щось на кшталт "if (x> 1) return;" чи вважатись ланцюжком двох тверджень разом?
Саймон Тевсі

1
@SimonTewsi Я вважаю, що returnце вважається заміною.
RastaJedi

@SimonTewsi Тут повертається неявно всередині блоку оператора if, тому воно є частиною оператора if, а не пов'язаним з ним. Компілятор дозволяє нам опустити дужки тут, оскільки це єдиний блок рядків.
користувач2597608

9

Ви можете знайти це у вікіпедії , але вирази оцінюються до деякого значення, тоді як заяви не мають оціненого значення.

Таким чином, вирази можна використовувати у висловлюваннях, але не навпаки.

Зауважте, що деякі мови (такі як Lisp, і я вважаю Ruby, та багато інших) не розмежовують твердження проти виразу ... у таких мовах все є виразом і може бути пов'язане з іншими виразами.


8

Для пояснення важливих відмінностей у складостійкості (ланцюговості) виразів та висловлювань, моїм улюбленим посиланням є документ про нагороду Джона Бекуса Тюрінга, чи можна програмування звільнити від стилю фон Неймана? .

Імперативні мови (Fortran, C, Java, ...) підкреслюють висловлювання для структурування програм і мають вирази як своєрідне задум. Функціональні мови підкреслюють вирази. Чисто функціональні мови мають такі потужні вирази, ніж твердження можна усунути взагалі.


5

Вираз можна оцінити, щоб отримати значення, тоді як заяви не повертають значення (вони недійсні ).

Вирази виклику функцій також можна вважати висловлюваннями, звичайно, але якщо середовище виконання не має спеціальної вбудованої змінної для утримання повернутого значення, немає можливості отримати його.

Мови, орієнтовані на твердження, вимагають, щоб усі процедури були переліком тверджень. Мови, орієнтовані на вираз, - це, мабуть, усі функціональні мови, - це списки виразів, або, у випадку LISP, один довгий S-вираз, який представляє список виразів.

Хоча обидва типи можуть складатися, більшість виразів можна складати довільно, доки типи збігаються. У кожного виду висловлювань є свій спосіб складання інших висловлювань, якщо вони можуть зробити це все. Передбачте, і якщо для заяв потрібна або одна стаття, або всі підпорядковані висловлювання входять у блок тверджень, один за одним, якщо тільки субстатації не дозволяють використовувати власні субстатації.

Виписки можуть також включати вирази, де вираз насправді не включає жодних висловлювань. Однак, одним з винятків буде лямбда-вираз, який представляє функцію, і тому може включати все, що функція може виключати, якщо мова не допускає лише обмежених лямбда, як лямбди з одновиразом Python.

У мові на основі виразів все, що вам потрібно, - це єдине вираження для функції, оскільки всі структури управління повертають значення (багато з них повертають NIL). У зворотному операторі немає необхідності, оскільки останнім оціненим виразом функції є повернене значення.


Тип оператора - це нижній тип. Voidне є нижчим типом. Дивіться мою відповідь .
Шелбі Мур III

1
Чи не є null тип нижнього типу (одне значення null)? Чи не voidбуде схожий на тип одиниці (але з її єдиним значенням недоступний)?
Марк Сідаде

Якщо voidтип повернення функції, яка ніколи не повертається (наприклад, функція, яка throwпомилка), це нижній тип . В іншому випадку voidце тип одиниці . Ви правильні, що твердження, яке не може розходитися, має тип одиниці. Але твердження, яке може розходитися, є нижчим типом. Через теорему зупинки ми зазвичай не можемо довести, що функція не розходиться, тому я думаю, що одиниця - це вигадка. Нижній тип не може мати значення, тому він не може мати єдине значення null.
Шелбі Мур III

1
Щодо того, що я сказав три роки тому, я не знаю, чи все ще вважаю твердження таким, що має тип пустоти чи якийсь тип. У мовах на основі висловлювань, з якими я знайомий, типи можуть мати лише значення та все, що зберігає або повертає значення (наприклад, вирази, змінні, члени та функції). Я, як правило, вважаю нижній тип порожнім набором (немає значень), і тому все, що не існує онтологічно, має такий тип. nullЗначення дійсно pseudovalue позначаючи , що посилання вказує на те , що не існує.
Марк Сідаде

1
Познач Я оцінив раціональність вашої відповіді. Ви в основному вийняли слова з моїх уст. І я сподіваюся, що було зрозуміло, що я визнав вам, що ви правильно підняли одиничну точку. Я думаю, що ми згодні. Я не збирався згадувати це, але, здається, деякі люди думають, що я негативно. Я просто намагаюся бути фактичним.
Шелбі Мур III

4

Просто: вираз оцінюється до значення, а вираз - ні.


Отже, що робить заява? Нічого?
Шелбі Мур III

1
Він може щось робити, але нічого не оцінює. Тобто, ви не можете призначити результат його змінної, тоді як ви можете з виразом.
Меттью Шинкель

І для цього заява повинна мати побічні ефекти, як стверджується моя сильно озвучена відповідь. Яка інша утиліта може мати заяву? Навіть якби NO-OP вважався твердженням (це лише "твердження" в граматиці, але не на шарі семантики, оскільки воно стирається після розбору та семантики - це те, що ми тут обговорюємо), це не пояснює, що саме чортів загальна корисність заяви.
Шелбі Мур III,

1
@ShelbyMooreIII Заяви не потрібно нічого робити або мати побічні ефекти. наприклад, {}це твердження. Введення слова в лапки від цього не змінює цього. Висловлювання - це синтаксичні конструкції із семантикою. Немає такого поняття, як "семантичний шар" - ти, схоже, маєш на увазі виконання . Ви кажете, що намагаєтесь бути точним, але в цьому вам не вдалося. Ваша скарга на "необізнаність виборців" є чистою hominem; у вас немає інформації про психічні стани низових людей.
Джим Балтер

Так, всі помиляються, окрім інтелектуально нечесних. {}визначається як висловлювання в мові C #.
Джим Балтер

4

Дещо про мови, засновані на виразах:


Найголовніше: все повертає значення


Немає різниці між фігурними дужками і дужками для розмежування кодових блоків та виразів, оскільки все є виразом. Це не перешкоджає лексичному оцінюванню, хоча: локальна змінна може бути визначена для виразу, в якому міститься її визначення, і всіх тверджень, що містяться в ньому, наприклад.


У мові, що базується на виразі, все повертає значення. Спочатку це може бути трохи дивним - Що (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()поверне якесь світове значення, таке як ОК, Готово або Успіх.
  • Коли декілька незв'язаних виразів оцінюються в межах одного більшого виразу, значення останнього, що оцінюється у великому виразі, стає значенням великого виразу. Якщо взяти приклад (FOR i = 1 TO 10 DO (print i)), значення циклу for 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
)

2

Висловлювання - це особливий випадок виразу, один із 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.


Висловлювання не є особливим випадком вираження. У деяких мовах (тобто у більшості наступників С) насправді навпаки.
Акангка

2

Виписки -> Інструкції слідувати послідовно
виразам -> Оцінка, яка повертає значення

Заяви в основному схожі на кроки або вказівки в алгоритмі, результатом виконання оператора є актуалізація вказівника інструкцій (так зване в асемблері)

Вирази не передбачають і порядок виконання з першого погляду, їх мета - оцінити та повернути значення. В імперативних мовах програмування оцінка виразу має порядок, але це лише через імперативну модель, але це не їх суть.

Приклади заяв:

for
goto
return
if

(усі вони означають перехід рядка (оператора) виконання на інший рядок)

Приклад виразів:

2+2

(це не означає ідею виконання, а оцінку)


А як щодо побічних ефектів?
Остін Генлі

@AustinHenley не вимагає цього. Насправді вираз однозначно може мати побічний ефект.
Акангка

1

Заява ,

Заява - це процедурна складова, з якої побудовані всі програми C #. Оператор може оголосити локальну змінну або константу, викликати метод, створити об'єкт або призначити значення змінній, властивості або полі.

Серія висловлювань, оточених фігурними дужками, утворює блок коду. Тіло методу - один із прикладів блоку коду.

bool IsPositive(int number)
{
    if (number > 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

Виписки в C # часто містять вирази. Вираз у C # - це фрагмент коду, що містить буквальне значення, просте ім’я або оператор та його операнди.

Вираз ,

Вираз - це фрагмент коду, який можна оцінити на одне значення, об'єкт, метод або простір імен. Два найпростіші типи виразів - це буквальні і прості назви. Буквал - це постійне значення, яке не має імені.

int i = 5;
string s = "Hello World";

І i, і прості імена, що ідентифікують локальні змінні. Коли ці змінні використовуються в виразі, значення змінної отримують і використовують для виразу.


Я краще напишу 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;}:)
Махді Тахсілдарі

1

Я віддаю перевагу значенню statementу формальному логічному сенсі цього слова. Саме ця змінює стан однієї або декількох змінних у обчисленні, дозволяючи зробити правдиве або хибне твердження про їх значення (значення).

Я думаю, що в світі обчислень та науці взагалі завжди буде плутанина, коли вводиться нова термінологія або слова, існуючі слова "переставляються" або користувачі не знають про існуючу, усталену або "належну" термінологію щодо того, що вони описують.


1

Я не дуже задоволений жодною з відповідей тут. Я переглянув граматику для 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 ++.

  • Вираз-вислів s самопояснюється (вислів може складатися з нуля або більше виразів, уважно читайте граматику, це складно)
  • caseнаприклад, це мітка-заява
  • селекція-оператор є if if/else,case
  • ітерація-заяву s є while, do...while,for (...)
  • перестрибуванням заяву s є break, continue, return(може повертати вираз),goto
  • заява-заява - це сукупність декларацій
  • try-block - оператор, що представляє try/catchблоки
  • і граматики може бути ще трохи

Це уривок, що показує частину виразів:

expression:
        assignment-expression
        expression "," assignment-expression
assignment-expression:
        conditional-expression
        logical-or-expression assignment-operator initializer-clause
        throw-expression
  • вирази є або містять часто призначення
  • умовно-вираз (звуки , вводить в оману) відноситься до використання операторів ( +, -, *, /, &, |, &&, ||, ...)
  • кидок-вираз - е-е? throwстановище є виразом занадто

0

Висловлювання - це граматично завершені речення. Вирази - ні. Наприклад

x = 5

читається як "х отримує 5." Це повне речення. Код

(x + 5)/9.0

читається, "х плюс 5 все поділено на 9,0". Це не повне речення. Заява

while k < 10: 
    print k
    k += 1

- повне речення. Зауважте, що заголовок циклу немає; "поки k <10", є підрядним пунктом.


whileє виразом деяких мов, таких як Scala. Ви плутаєте граматику з набиранням тексту. Дивіться мою відповідь .
Шелбі Мур III

Ось цикл while у scala: tutorialspoint.com/scala/scala_time_loop.htm Цикл із його присудком і жодним тілом не є граматично повним реченням. Це не повний вираз. Вам потрібне тіло, щоб завершити його як вираз.
ncmathsadist

A whileз тілом все ще є виразом у Scala. Це також може бути твердженням, якщо воно створює побічні ефекти, що дозволяє моя сильно прихильна відповідь (вираз також може бути твердженням). Моя відповідь - єдино правильна. Вибачте за всіх тих читачів, які не можуть зрозуміти.
Шелбі Мур III,

Що ви маєте на увазі під граматично закінченим? В C, (x + 5)/9.0безумовно , може стояти окремо як твердження. Крім того, якщо під граматичним завершенням ви маєте на увазі дійсну програму, C не дозволяє операторам окремо стояти як одна програма.
Акангка

Граматично закінчений: складає повне речення.
ncmathsadist

0

Ось один із найпростіших відповідей, які я знайшов.

Спочатку відповів Anders Kaseorg

Оператор - це повний рядок коду, який виконує якусь дію, а вираз - це будь-який розділ коду, який оцінює значення.

Вирази можна комбінувати «горизонтально» у більші вирази за допомогою операторів, тоді як висловлювання можна комбінувати лише «вертикально», записуючи одне за одним, або з блоковими конструкціями.

Кожен вираз може використовуватися як вислів (ефект якого полягає в оцінці виразу та ігноруванні отриманого значення), але більшість висловлювань не можна використовувати як вирази.

http://www.quora.com/Python-programming-language-1/Whats-the-difference-bet between-a-statement-and-an-expression-in-Python


0

Фактичною основою цих понять є:

Вирази : синтаксична категорія, екземпляр якої можна оцінити до значення.

Заява : синтаксична категорія, екземпляр якої може бути пов'язаний з оцінкою виразу, і отримане значення оцінки (якщо воно є) не гарантується.

Окрім самого початкового контексту для FORTRAN на початку десятиліть, як визначення виразів, так і твердження у прийнятій відповіді, очевидно, помилкові:

  • Вирази можуть бути неоціненими операндами. Цінності ніколи не виробляються з них.
    • Субекспресії в не строгих оцінках можуть бути безумовно неоцінені.
      • Більшість мов, подібних С, мають так звані правила оцінки короткого замикання, щоб умовно пропустити деякі оцінки піддекспресії, а не змінити кінцевий результат, незважаючи на побічні ефекти.
    • С та деякі С-подібні мови мають поняття про неоцінений операнд, який може бути навіть нормативно визначений у специфікації мови. Такі конструкції використовуються для остаточного уникнення оцінок, тому інформацію про контекст (наприклад, типи або вимоги до вирівнювання) можна статично розрізнити, не змінюючи поведінку після перекладу програми.
      • Наприклад, вираз, який використовується як операнд sizeofоператора, ніколи не оцінюється.
  • Заяви не мають нічого спільного з лінійними конструкціями. Вони можуть робити щось більше, ніж вирази, залежно від мовних специфікацій.
    • Сучасний Fortran, як прямий нащадок старого FORTRAN, має концепції виконавчого оператора s та невиконаного твердження s.
    • Аналогічно, C ++ визначає декларації як підкатегорію верхнього рівня одиниці перекладу. Декларація в C ++ - це твердження. (Це не вірно в C.) Є також вираз-твердження , подібні виконуваним операторам Fortran.
    • Для інтересу порівняння з виразами мають значення лише "виконувані" заяви. Але ви не можете ігнорувати той факт, що заяви вже узагальнені як конструкції, що формують одиниці перекладу на таких імперативних мовах. Отже, як бачите, визначення категорії сильно різняться. Є, що, мабуть, є єдиною загальною властивістю, що збереглася серед цих мов, - це те, що очікується, що твердження будуть інтерпретовані у лексичному порядку (для більшості користувачів - зліва направо та зверху вниз).

(BTW, я хочу додати [цитування необхідних] до цієї відповіді, що стосується матеріалів про C, оскільки я не можу згадати, чи є у DMR такі думки. Здається, це не так, інакше не повинно бути причин для збереження дублювання функціональності в дизайні C : помітно, оператор кома проти тверджень.)

(Наступне обґрунтування не є прямою відповіддю на початкове запитання, але я вважаю за потрібне уточнити щось, про що вже відповіли.)

Тим не менш, сумнівно, що нам потрібна конкретна категорія "висловлювань" мовами програмування загального призначення:

  • Гарантовано, що заяви не матимуть більше смислових можливостей щодо виразів у звичайних конструкціях.
    • Багато мов уже успішно відмовляються від поняття тверджень, щоб отримати чисті, акуратні та послідовні загальні конструкції.
      • У таких мовах вирази можуть робити все, що може зробити висловлювання старого стилю: просто скинути невикористані результати, коли вирази оцінюються, або залишаючи результати явно невизначеними (наприклад, у схемі R n RS), або маючи особливе значення (як значення одиничного типу), які не можна отримати за допомогою звичайних оцінок виразів.
      • Правила лексичного порядку оцінки виразів можуть бути замінені оператором явного керування послідовністю (наприклад, beginу схемі) або синтаксичним цукром монадичних структур.
      • Правила лексичного порядку інших видів "тверджень" можуть бути отримані як синтаксичні розширення (наприклад, використовуючи гігієнічні макроси), щоб отримати подібний синтаксичний функціонал. (І насправді це може зробити більше .)
    • Навпаки, висловлювання не можуть мати таких загальноприйнятих правил, оскільки вони не складають оцінку: просто немає такого загального поняття "оцінка заступників". (Навіть якщо є, я сумніваюся, що може існувати щось набагато більше, ніж скопіювати та вставити з існуючих правил оцінювання виразів.)
      • Як правило, мови, що зберігають висловлювання, також матимуть вирази для вираження обчислень, і існує підкатегорія вищого рівня висловлювань, що зберігається для оцінок виразів для цієї підкатегорії. Наприклад, C ++ має так звану вираз-оператор як підкатегорію і використовує правила оцінки виразного значення, що відкидаються, для визначення загальних випадків оцінок повного вираження в такому контексті. Деякі мови, такі як C #, вирішують уточнювати контексти для спрощення випадків використання, але це більше розширює специфікацію.
  • Для користувачів мов програмування значення висловлювань може ще більше їх заплутати.
    • Розмежування правил виразів і висловлювань на мовах вимагає більше зусиль для вивчення мови.
    • Наївне тлумачення лексичного порядку приховує більш важливе поняття: оцінка вираження. (Це, мабуть, найбільш проблематично за всіх.)
      • Навіть оцінки повних виразів у висловлюваннях обмежують лексичний порядок, піддекспресії не є (обов’язково). Зрештою, користувачі повинні дізнатися це, крім будь-яких правил, пов'язаних із твердженнями. (Поміркуйте, як змусити новачка зрозуміти, що це++i + ++i безглузду C.)
      • Деякі мови, такі як Java та C #, додатково обмежують порядок оцінювання піддепресій, щоб дозволити незнання правил оцінювання. Це може бути ще більш проблематично.
        • Це здається завищеним для користувачів, які вже засвоїли ідею оцінки вираження. Це також заохочує спільноту користувачів слідувати розмитій ментальній моделі дизайну мови.
        • Це ще більше посилює специфікацію мови.
        • Оптимізація шкідлива, втрачаючи виразність недетермінізму в оцінках до введення більш складних примітивів.
      • Кілька мов на зразок C ++ (зокрема, C ++ 17) визначають більш тонкий контекст правил оцінювання як компроміс вищезазначених проблем.
        • Це сильно роздуває специфікацію мови.
        • Це суперечить простоті середнім користувачам ...

То чому заяви? Так чи інакше, історія вже безлад. Здається, більшість мовних дизайнерів не ставляться до свого вибору ретельно.

Гірше, що він навіть дає деяким ентузіастам системного типу (які недостатньо знайомі з історією PL) деякі помилки, що типові системи повинні мати важливе значення для більш важливих конструкцій правил з оперативної семантики.

Серйозно, міркування залежно від типів у багатьох випадках не так вже й погано, але особливо не конструктивні в цьому спеціальному. Навіть експерти можуть накрутити речі.

Наприклад, хтось наголошує на чітко набраному характері як на центральному аргументі проти традиційного поводження з небажаним продовженням . Хоча висновок дещо розумний, і розуміння складених функцій добре ( але все ще далеко наївне до суті ), цей аргумент не є надійним, оскільки він повністю ігнорує підхід "бічного каналу" на практиці, як _Noreturn any_of_returnable_types(у С11) для кодування Falsum. І строго кажучи, абстрактна машина з непередбачуваним станом не тотожна "розбитому комп'ютеру".


0

У мові програмування, орієнтованої на твердження, блок коду визначається як список операторів. Іншими словами, оператор - це фрагмент синтаксису, який можна помістити всередині кодового блоку, не викликаючи синтаксичної помилки.

Вікіпедія визначає словосполучення аналогічно

У комп’ютерному програмуванні оператор - це синтаксична одиниця імперативної мови програмування, яка виражає певні дії, які слід здійснити. Програма, написана такою мовою, формується послідовністю одного або декількох висловлювань

Зауважте останнє твердження. (хоча "програма" в цьому випадку технічно неправильна, оскільки і C, і Java відкидають програму, яка не складається з нічого з тверджень.)

Вікіпедія визначає вираз слова як

Вираз у мові програмування є синтаксичним утворенням, яке може бути оцінено для визначення його значення

Це, однак, помилково, оскільки в Котліні throw new Exception("")це вираз, але, коли його оцінюють, він просто кидає виняток, ніколи не повертаючи жодного значення.

У статизованій мові програмування кожен вираз має тип. Однак це визначення не працює в динамічно набраній мові програмування.

Особисто я визначаю вираз як фрагмент синтаксису, який можна скласти з оператором або функцією викликів, щоб отримати більший вираз. Це насправді схоже на пояснення вираження у Вікіпедії:

Це комбінація однієї або декількох констант, змінних, функцій та операторів, які програма програмування інтерпретує (відповідно до її специфічних правил пріоритетності та асоціації) та обчислює для отримання ("повернення" у стані) інше значення

Але проблема полягає в мові програмування на C, задану функцію ExecuteSomething like this:

void executeSomething(void){
    return;
}

Це executeSomething()вираз чи це твердження? Згідно з моїм визначенням, це твердження, тому що, як визначено у довідковій граматиці Microsoft C,

Ви не можете використовувати (неіснуюче) значення виразу, який має тип void будь-яким способом, а також не можете перетворити недійсний вираз (шляхом неявного або явного перетворення) в будь-який тип, крім void

Але ця ж сторінка чітко вказує, що такий синтаксис є виразом.


-6

Для вдосконалення та затвердження моєї попередньої відповіді, визначення термінів мови програмування слід пояснювати з теорії типів інформатики, коли це застосовується.

Вираз має тип, відмінний від типу Bottom, тобто має значення. Заява має тип Unit або Bottom.

З цього випливає, що оператор може мати будь-який ефект у програмі лише тоді, коли створює побічний ефект, тому що він або не може повернути значення, або лише повертає значення типу Unit, яке або неможливо визначити (у деяких мовах таке a C void) або (наприклад, у Scala) можуть бути збережені для затримки оцінки твердження.

Очевидно, що a @pragmaабо a /*comment*/не мають типу, і тому вони відрізняються від тверджень. Таким чином, єдиним типом твердження, яке не матиме побічних ефектів, було б недіяння. Недіяльність корисна лише як заповнювач для майбутніх побічних ефектів. Будь-яка інша дія через висловлювання буде побічним ефектом. Знову ж натяк компілятора, наприклад @pragma, не є твердженням, оскільки він не має типу.


2
Розрізнення не має нічого спільного з типом виразів. Синтаксично визначені висловлювання взагалі не мають типів у багатьох мовах. Хоча теоретично я не проти призначати тип на таких термінах, різні трактування щодо @pragmaабо /*comment*/є логічно непослідовними.
FrankHB

-11

Найбільш точно, оператор повинен мати «побічний ефект» (тобто бути обов'язковим ) та вираз має мати на значення типу (тобто не нижній тип).

Типу заяви є типом блоку, але з - за зупиняючи теореми блоку вигадки так що дозволяє сказати нижній тип .


Voidце не саме нижній тип (це не підтип усіх можливих типів). Він існує в мовах, які не мають повністю звукової системи . Це може звучати як вислів снобізму, але повнота, наприклад, анотації з дисперсією, є критично важливою для написання розширюваного програмного забезпечення.

Давайте подивимось, що Вікіпедія має сказати з цього приводу.

https://en.wikipedia.org/wiki/Statement_(computer_science)

У комп'ютерному програмуванні заява - це найменший окремий елемент імперативної мови програмування, який виражає певну дію, яку слід здійснити.

Багато мов (наприклад, C) роблять відмінність між операторами та визначеннями, при цьому оператор містить лише виконуваний код та визначення, що декларує ідентифікатор, тоді як вираз оцінює лише значення.


5
Заява не повинна мати побічний ефект. Наприклад, у python passє твердженням. Це неоперація, і вона нічого не оцінює.
Меттью Шинкель

9
-1 Це неправильно. Оператор не має мати побічний ефект. Дивіться розділ 1.5 специфікації мови C # . Мало того, що НЕ вказано , що заяви повинні мати побічні ефекти, але він також перераховує кілька заяв , які не можуть мати НЕ побічні ефекти.
NullUserException

2
@NullUserException Я прочитав цей розділ. Заяви, декларації, вираження, вибір, повторення та стрибки можуть створювати побічні ефекти. Але якщо є вираз RT, то це не твердження. Я усвідомлюю, що специфікація є прирівнюванням виразів до висловлювань, але це питання вимагає різниці між ними. Отже, або на питання немає відповіді, або ви сприймаєте специфікацію C # занадто буквально. Відповідь вгорі пробує сказати, що я зробив. Але "робити щось" безглуздо. "побічний ефект" - це змістовний спосіб сказати "щось робить". Треба думати, а не просто відригувати.
Шелбі Мур III

13
@ShelbyMooreIII Ви маєте рацію. Офіційна документація неправильна . Марк Гравелл і Джон Скіт, які, можливо, найбільш поважають плакатів на C #, що діють на ЗП поза Еріком Ліппертом, помиляються . Я та всі інші, хто звернувся до вас і залишили коментарі, що пояснюють нашу позицію, помиляються . Ти правий. Ви, очевидно, єдина людина, яка знає, про що вони говорять, оскільки ви настільки розумніші, ніж усі інші.
NullUserException

3
Знання точного визначення таких понять, як твердження, вираз, керування, перетворення тощо має нульовий вплив на 99,999% повсякденних завдань програмування. Подумайте над цим . Також більшість людей не хвилюються до Хаскелл та Скали.
NullUserException
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.