Wyrażenie a wyrażenie


431

Pytam w odniesieniu do c #, ale zakładam, że jest tak samo w większości innych języków.

Czy ktoś ma dobrą definicję wyrażeń i stwierdzeń i jakie są różnice?


4
Odpowiedź, którą wybrałeś, jest dla mnie niejednoznaczna. Wyrażenie również coś robi - ocenia na wartość. Udzieliłem jednoznacznej odpowiedzi.
Shelby Moore III,

4
@ShelbyMooreIII - Niejednoznaczne i również błędne. Przyjęta odpowiedź jest sformułowana w sposób nieformalny, ale to sformułowanie ułatwia zrozumienie - a co najważniejsze, przekazane znaczenie jest dokładne.
Justin Morgan

@JustinMorgan Niestety, definicje w zaakceptowanej odpowiedzi są oczywiście błędne („ocenia na wartość” / „wiersz kodu”) w przypadku większości współczesnych języków obejmują języki podobne do C: wyrażenia mogą być używane w nieocenionych kontekstach, a instrukcje nie mają nic zrobić z liniami. Nawet w przypadku niektórych wyjaśnień krótka odpowiedź jest myląca i myląca.
FrankHB,

Odpowiedzi:


520

Wyrażenie: Coś, co daje wartość. Przykład: 1 + 2 / x
Instrukcja: Linia kodu, która coś robi. Przykład: GOTO 100

W najwcześniejszych językach programowania ogólnego przeznaczenia, takich jak FORTRAN, rozróżnienie było bardzo wyraźne. W FORTRAN instrukcja była jedną z jednostek wykonawczych. Jedynym powodem, dla którego nie był nazywany „linią”, było to, że czasami obejmował wiele linii. Samo wyrażenie nie mogło nic zrobić ... musiałeś przypisać je do zmiennej.

1 + 2 / X

jest błędem w FORTRAN, ponieważ nic nie robi. Musiałeś zrobić coś z tym wyrażeniem:

X = 1 + 2 / X

FORTRAN nie miał gramatyki, jaką znamy dzisiaj - ten pomysł został wymyślony wraz z Formą Backus-Naur (BNF), jako część definicji Algolu-60. W tym momencie rozróżnienie semantyczne („mieć wartość” w porównaniu z „zrób coś”) zostało zapisane w składni : jeden rodzaj wyrażenia był wyrażeniem, a drugi wyrażeniem, a parser mógł je rozróżnić.

Projektanci późniejszych języków zatarli to rozróżnienie: zezwalali na różne wyrażenia syntaktyczne i zezwalali na wyrażenia składniowe o wartościach. Najwcześniejszym popularnym przykładem języka, który wciąż istnieje, jest C. Projektanci C zdali sobie sprawę, że nie zaszkodzi, jeśli pozwolisz ocenić wyrażenie i wyrzucić wynik. W języku C każde wyrażenie składniowe może zostać przekształcone w wyrażenie po prostu poprzez wstawienie średnika na końcu:

1 + 2 / x;

jest całkowicie uzasadnionym stwierdzeniem, chociaż absolutnie nic się nie wydarzy. Podobnie w C wyrażenie może mieć skutki uboczne - może coś zmienić.

1 + 2 / callfunc(12);

ponieważ callfuncmoże po prostu zrobić coś pożytecznego.

Gdy zezwolisz, by dowolne wyrażenie było instrukcją, możesz również pozwolić operatorowi przypisania (=) wewnątrz wyrażeń. Właśnie dlatego C pozwala ci robić takie rzeczy

callfunc(x = 2);

Ocenia to wyrażenie x = 2 (przypisując wartość 2 do x), a następnie przekazuje to (2) do funkcji callfunc.

To rozmycie wyrażeń i instrukcji występuje we wszystkich pochodnych C (C, C ++, C # i Java), które wciąż mają niektóre instrukcje (jak while), ale które pozwalają na użycie niemal dowolnego wyrażenia jako instrukcji (w przypisaniu tylko w języku C #, wyrażenia wywołania, inkrementacji i dekrementacji mogą być użyte jako oświadczenia; patrz odpowiedź Scotta Wiśniewskiego ).

Posiadanie dwóch „kategorii składniowych” (co jest techniczną nazwą tego rodzaju instrukcji i wyrażeń rzeczowych) może prowadzić do powielania wysiłku. Na przykład C ma dwie formy warunkowe, formę instrukcji

if (E) S1; else S2;

i forma wyrażenia

E ? E1 : E2

A czasem ludzie chcą duplikacji, której tam nie ma: na przykład w standardowym C tylko instrukcja może deklarować nową zmienną lokalną - ale ta zdolność jest na tyle użyteczna, że ​​kompilator GNU C zapewnia rozszerzenie GNU, które umożliwia wyrażeniu deklarację zmienna lokalna również.

Projektanci innych języków nie lubili tego rodzaju powielania i na początku zauważyli, że jeśli wyrażenia mogą mieć skutki uboczne, a także wartości, to rozróżnienie składniowe między wyrażeniami a wyrażeniami nie jest aż tak przydatne - więc się go pozbyli . Haskell, Icon, Lisp i ML to wszystkie języki, które nie mają instrukcji składniowych - mają tylko wyrażenia. Nawet pętle strukturalne i formy warunkowe są uważane za wyrażenia i mają wartości - ale niezbyt interesujące.


9
Jeśli cię tu nie interpretuję, wydaje się, że twierdzisz, że „(gęś setf (trzecia foo))” jest wyrażeniem, a nie stwierdzeniem, zarówno dlatego, że jest to Lisp, który „nie ma instrukcji”, i ponieważ Lisp jest o ponad dekadę starszy od C, który był „najwcześniejszym popularnym językiem, który zacierał linie [między wyrażeniami a stwierdzeniami]”. Czy mógłby mi wyjaśnić szczegóły tego?
cjs

2
@Curt Sampson, czy zadałeś to pytanie jako osobne pytanie?
Kelly S. French

5
Jeśli się nie mylę, callfunc(x = 2);przechodzi xna callfuncnie 2. Jeśli xjest zmiennoprzecinkowe, callfunc(float)zostanie wywołane, a nie callfunc(int). A w C ++, jeśli przejdziesz x=ydo funci funcodniesiesz odniesienie i je zmienisz , to się zmieni x, a nie y.
Gabriel

W powyższej odpowiedzi napisano, że „Haskell, ... to wszystkie języki, które nie mają instrukcji składniowych - mają tylko wyrażenia”. Jestem ciekawy, dlaczego whereklauzula w haskell jest uważana za wyrażenie, a nie stwierdzenie. learnyouahaskell.com/syntax-in-functions#where
skgbanga

@skgbanga Wierzę, że w whererzeczywistości jest częścią deklaracji funkcji, a nie wyrażenia lub instrukcji.
Akangka

22
  • wyrażenie to wszystko, co daje wartość: 2 + 2
  • instrukcja jest jednym z podstawowych „bloków” wykonywania programu.

Zauważ, że w C „=” jest w rzeczywistości operatorem, który wykonuje dwie rzeczy:

  • zwraca wartość podwyrażenia prawej ręki.
  • kopiuje wartość podwyrażenia prawej ręki do zmiennej po lewej stronie.

Oto fragment gramatyki ANSI C. Widzisz, że C nie ma wielu różnych rodzajów instrukcji ... większość instrukcji w programie to instrukcje wyrażeń, tzn. Wyrażenia ze średnikiem na końcu.

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
Niepoprawna logika tego, czym jest instrukcja. Program deklaratywny może również zostać uruchomiony, ale program deklaratywny nie ma instrukcji. Stwierdzenie jest i ma „skutki uboczne” , tzn. Jest konieczne. por. moja odpowiedź .
Shelby Moore III,

15

Wyrażenie to coś, co zwraca wartość, podczas gdy instrukcja nie.

Dla przykładów:

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

Najważniejszą rzeczą między nimi jest to, że możesz łączyć wyrażenia razem, podczas gdy instrukcji nie można łączyć w łańcuchy.


6
Pewne wypowiedzi mogą być powiązane. {stmt1; stmt2; stmt3;} to łańcuch, a także sama instrukcja (złożona).
Hugh Allen,

5
foo.voidFunc(1);jest wyrażeniem o pustej wartości. whilei ifsą oświadczeniami.
tzot

Ciekawi mnie brak łączenia łańcuchów wypowiedzi. Czy coś w stylu „jeśli (x> 1) zwróci;” być uważanym za łączenie dwóch zdań razem?
Simon Tewsi

1
@ SimonTewsi Uważam, że returnjest to uważane za podstację.
RastaJedi

@ SimonTewsi Instrukcja return tutaj jest domyślnie zawarta w bloku instrukcji if, więc jest częścią instrukcji if, a nie jest z nią połączona. Kompilator pozwala nam pominąć nawiasy klamrowe, ponieważ jest to blok jednowierszowy.
user2597608

9

Możesz to znaleźć na wikipedii , ale wyrażenia są oceniane do pewnej wartości, podczas gdy wyrażenia nie mają wartości ocenianej.

Tak więc wyrażeń można używać w instrukcjach, ale nie na odwrót.

Zauważ, że niektóre języki (takie jak Lisp i, jak sądzę, Ruby i wiele innych) nie rozróżniają wyrażenia a wyrażenia ... w takich językach wszystko jest wyrażeniem i może być powiązane z innymi wyrażeniami.


8

Aby wyjaśnić ważne różnice w kompozycyjności (łańcuchowości) wyrażeń a wyrażeń, moim ulubionym odniesieniem jest artykuł z nagrodami Turinga Johna Backusa: Czy programowanie można wyzwolić ze stylu von Neumanna? .

Języki imperatywne (Fortran, C, Java, ...) kładą nacisk na instrukcje dla programów tworzących struktury i mają wyrażenia jako swego rodzaju refleksję. Języki funkcjonalne podkreślają wyrażenia. Czysto funkcjonalne języki mają tak potężne wyrażenia, że ​​można całkowicie wyeliminować instrukcje.


5

Wyrażenia można oceniać w celu uzyskania wartości, podczas gdy instrukcje nie zwracają wartości (są typu void ).

Wyrażenia wywołania funkcji można również oczywiście uważać za instrukcje, ale jeśli środowisko wykonawcze nie ma specjalnej wbudowanej zmiennej do przechowywania zwracanej wartości, nie ma możliwości jej odzyskania.

Języki zorientowane na instrukcje wymagają, aby wszystkie procedury były listą instrukcji. Języki zorientowane na wyrażenia, które prawdopodobnie są wszystkimi językami funkcjonalnymi, są listami wyrażeń lub, w przypadku LISP, jednym długim wyrażeniem S reprezentującym listę wyrażeń.

Mimo że oba typy można komponować, większość wyrażeń można komponować dowolnie, o ile typy są do siebie dopasowane. Każdy typ instrukcji ma swój własny sposób komponowania innych instrukcji, jeśli potrafią to zrobić wszystko. Foreach i jeśli instrukcje wymagają albo jednej instrukcji, albo że wszystkie podrzędne instrukcje idą w bloku instrukcji, jedna po drugiej, chyba że podstacje pozwalają na własne podstacje.

Instrukcje mogą również zawierać wyrażenia, w których wyrażenie tak naprawdę nie zawiera żadnych instrukcji. Jedynym wyjątkiem byłoby wyrażenie lambda, które reprezentuje funkcję, a zatem może obejmować wszystko, co funkcja może wykluczyć, chyba że język dopuszcza tylko ograniczone lambdy, takie jak lambda z pojedynczym wyrażeniem Pythona.

W języku opartym na wyrażeniach wystarczy jedno wyrażenie dla funkcji, ponieważ wszystkie struktury kontrolne zwracają wartość (wiele z nich zwraca NIL). Nie ma potrzeby instrukcji return, ponieważ ostatnio oceniane wyrażenie w funkcji jest wartością zwracaną.


Typ instrukcji jest typem dolnym. Voidnie jest typem dolnym. Zobacz moją odpowiedź .
Shelby Moore III,

1
Czy typ zerowy nie jest typem dolnym (pojedyncza wartość null)? Czy nie voidbyłby bardziej podobny do typu jednostki (ale z jedną wartością niedostępną)?
Mark Cidade,

Jeśli voidjest to typ zwracany przez funkcję, która nigdy nie zwraca (np. Funkcja, która throwjest błędem), jest to typ dolny . W przeciwnym razie voidjest typ jednostki . Masz rację, że stwierdzenie, które nie może się różnić, ma typ jednostki. Ale stwierdzenie, które może się różnić, jest typem podstawowym. Z powodu twierdzenia Haltinga zwykle nie możemy udowodnić, że funkcja się nie rozbiera, więc myślę, że jednostka to fikcja. Typ dolny nie może mieć wartości, więc nie może mieć pojedynczej wartości null.
Shelby Moore III,

1
Jeśli chodzi o to, co powiedziałem trzy lata temu, nie wiem, czy nadal uważam, że stwierdzenia mają typ pustki lub jakikolwiek inny rodzaj. W językach opartych na instrukcjach, które znam, tylko wartości i wszystko, co przechowuje lub zwraca wartość (np. Wyrażenia, zmienne, elementy i funkcje) może mieć typy. Ogólnie myślę o dolnym typie jako pustym zestawie (bez wartości), więc wszystko, co nie istnieje ontologicznie, miałoby ten typ. nullWartość jest naprawdę pseudovalue oznaczający, że odwołanie odnosi się do czegoś, co nie istnieje.
Mark Cidade,

1
Mark Doceniam racjonalność twojej odpowiedzi. Zasadniczo wyjąłeś słowa z moich ust I mam nadzieję, że było jasne, że przyznałem ci, że miałeś rację, podnosząc punkt jednostkowy. Myślę, że się zgadzamy. Nie zamierzałam zawracać sobie głowy wspominaniem o tym, ale wydaje się, że niektórzy ludzie myślą, że jestem negatywny. Po prostu staram się być szczery.
Shelby Moore III,

4

Po prostu: wyrażenie zwraca wartość, a instrukcja nie.


Co robi zdanie? Nic?
Shelby Moore III,

1
Potrafi coś zrobić, ale niczego nie ocenia. To znaczy, nie możesz przypisać wyniku do zmiennej, podczas gdy możesz z wyrażeniem.
Matthew Schinckel,

Dlatego oświadczenie musi mieć skutki uboczne, jak głosi moja mocno odrzucona odpowiedź. Jakie inne narzędzie może mieć takie oświadczenie? Nawet jeśli NO-OP uznano za oświadczenie (jest to tylko „oświadczenie” w gramatyce, ale nie w warstwie semantyki, ponieważ jest usuwane po analizie, a semantyka jest tutaj omawiana), nie wyjaśniałoby cholera ogólna użyteczność instrukcji to.
Shelby Moore III,

1
@ShelbyMooreIII Oświadczenia nie muszą nic robić ani mieć skutków ubocznych. np. {}jest stwierdzeniem. Umieszczenie tego słowa w przerażających cytatach tego nie zmienia. Instrukcje są konstrukcjami składniowymi z semantyką. Nie ma czegoś takiego jak „warstwa semantyki” - wydaje się, że masz na myśli wykonanie . Mówisz, że próbujesz być dokładny, ale ci się to nie udało. Wasza skarga na „ignorancję słabszych wyborców” jest czysta ad hominem; nie masz informacji o stanach mentalnych downvoters.
Jim Balter

Tak, wszyscy się mylą, z wyjątkiem intelektualnie nieuczciwych. {}jest zdefiniowany jako instrukcja w specyfikacji języka C #.
Jim Balter,

4

Niektóre rzeczy na temat języków opartych na wyrażeniach:


Najważniejsze: wszystko zwraca wartość


Nie ma różnicy między nawiasami klamrowymi i nawiasami klamrowymi do ograniczania bloków kodu i wyrażeń, ponieważ wszystko jest wyrażeniem. Nie zapobiega to jednak zakresowi leksykalnemu: na przykład można zdefiniować zmienną lokalną dla wyrażenia, w którym zawarta jest jej definicja, i wszystkie zawarte w niej instrukcje.


W języku opartym na wyrażeniach wszystko zwraca wartość. Na początku może to być trochę dziwne - co (FOR i = 1 TO 10 DO (print i))powraca?

Kilka prostych przykładów:

  • (1) zwroty 1
  • (1 + 1) zwroty 2
  • (1 == 1) zwroty TRUE
  • (1 == 2) zwroty FALSE
  • (IF 1 == 1 THEN 10 ELSE 5) zwroty 10
  • (IF 1 == 2 THEN 10 ELSE 5) zwroty 5

Kilka bardziej złożonych przykładów:

  • Niektóre rzeczy, takie jak niektóre wywołania funkcji, naprawdę nie mają znaczącej wartości do zwrócenia (Rzeczy, które powodują jedynie skutki uboczne?). Wywołanie OpenADoor(), FlushTheToilet()lub TwiddleYourThumbs()zwróci jakąś przyziemną wartość, taką jak OK, Gotowe lub Sukces.
  • Kiedy wiele niepowiązanych wyrażeń jest ocenianych w ramach jednego większego wyrażenia, wartość ostatniej rzeczy ocenianej w dużym wyrażeniu staje się wartością dużego wyrażenia. Na przykład (FOR i = 1 TO 10 DO (print i)), wartość pętli for wynosi „10”, powoduje to, że (print i)wyrażenie jest oceniane 10 razy, za każdym razem zwracając i jako ciąg. Ostateczny czas dzięki powrotom 10, nasza ostateczna odpowiedź

Często wymaga niewielkiej zmiany sposobu myślenia, aby jak najlepiej wykorzystać język oparty na wyrażeniach, ponieważ fakt, że wszystko jest wyrażeniem, umożliwia „wstawienie” wielu rzeczy

Jako szybki przykład:

 FOR i = 1 to (IF MyString == "Hello, World!" THEN 10 ELSE 5) DO
 (
    LotsOfCode
 )

jest całkowicie poprawnym zamiennikiem nieopartego na wyrażeniach

IF MyString == "Hello, World!" THEN TempVar = 10 ELSE TempVar = 5 
FOR i = 1 TO TempVar DO
(    
    LotsOfCode  
)

W niektórych przypadkach układ, na który pozwala kod oparty na wyrażeniach, jest dla mnie znacznie bardziej naturalny

Oczywiście może to doprowadzić do szaleństwa. W ramach projektu hobby w opartym na wyrażeniach języku skryptowym MaxScript udało mi się wymyślić tę potworną linię

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

Instrukcja jest szczególnym przypadkiem wyrażenia, z voidtypem. Tendencja języków do odmiennego traktowania oświadczeń często powoduje problemy i byłoby lepiej, gdyby były odpowiednio uogólnione.

Na przykład w języku C # mamy bardzo przydatny Func<T1, T2, T3, TResult>przeciążony zestaw ogólnych delegatów. Ale musimy również mieć odpowiedni Action<T1, T2, T3>zestaw, a programowanie wyższego rzędu ogólnego przeznaczenia musi być ciągle powielane, aby poradzić sobie z tym niefortunnym rozwidleniem.

Trywialny przykład - funkcja, która sprawdza, czy referencja jest pusta przed wywołaniem innej funkcji:

TResult IfNotNull<TValue, TResult>(TValue value, Func<TValue, TResult> func)
                  where TValue : class
{
    return (value == null) ? default(TValue) : func(value);
}

Czy kompilator mógłby poradzić sobie z możliwością TResultbycia void? Tak. Wystarczy, że po znaku return pojawi się wyrażenie typu void. Wynik default(void)byłby typu void, a przekazywany func musiałby mieć postać Func<TValue, void>(która byłaby równoważna Action<TValue>).

Szereg innych odpowiedzi sugeruje, że nie można łączyć wyrażeń jak w wyrażeniach, ale nie jestem pewien, skąd pochodzi ten pomysł. Możemy myśleć o tym, ;że pojawia się po instrukcjach jako o binarnym operatorze poprawki, przyjmującym dwa wyrażenia typu voidi łączącym je w jedno wyrażenie typu void.


Instrukcja nie jest szczególnym przypadkiem wyrażenia. W niektórych językach (tj. W większości następców C) jest odwrotnie.
Akangka

2

Instrukcje -> Instrukcje sekwencyjne
Wyrażenia -> Ocena, która zwraca wartość

Instrukcje są w zasadzie krokami lub instrukcjami w algorytmie, wynikiem wykonania instrukcji jest aktualizacja wskaźnika instrukcji (tzw. W asemblerze)

Wyrażenia nie implikują i kolejność wykonywania na pierwszy rzut oka, ich celem jest ocena i zwrócenie wartości. W imperatywnych językach programowania ocena wyrażenia ma porządek, ale dzieje się tak tylko z powodu modelu imperatywnego, ale nie jest to ich istotą.

Przykłady wyciągów:

for
goto
return
if

(wszystkie implikują przejście linii (instrukcji) wykonania do innej linii)

Przykład wyrażeń:

2+2

(nie implikuje pomysłu wykonania, ale oceny)


Co z efektami ubocznymi?
Austin Henley,

@AustinHenley nie ma na to żadnych wymagań. W rzeczywistości wyrażenie może zdecydowanie wywołać efekt uboczny.
Akangka

1

oświadczenie ,

Instrukcja jest składnikiem proceduralnym, z którego zbudowane są wszystkie programy C #. Instrukcja może deklarować lokalną zmienną lub stałą, wywołać metodę, utworzyć obiekt lub przypisać wartość do zmiennej, właściwości lub pola.

Szereg instrukcji otoczony nawiasami klamrowymi tworzy blok kodu. Treść metody jest jednym przykładem bloku kodu.

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

Instrukcje w języku C # często zawierają wyrażenia. Wyrażenie w języku C # to fragment kodu zawierający wartość literalną, prostą nazwę lub operator i jego operandy.

Wyrażenie ,

Wyrażenie jest fragmentem kodu, który można ocenić jako jedną wartość, obiekt, metodę lub przestrzeń nazw. Dwa najprostsze typy wyrażeń to literały i proste nazwy. Literał to stała wartość, która nie ma nazwy.

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

Zarówno i i s to proste nazwy identyfikujące zmienne lokalne. Gdy zmienne te są używane w wyrażeniu, wartość zmiennej jest pobierana i wykorzystywana do wyrażenia.


Wolę pisać, if(number >= 0) return true; else return false;a nawet lepiej bool? IsPositive(int number) { if(number > 0) return true; else if(number < 0) return false; else return null;}:)
Mahdi Tahsildari

1

Wolę znaczenie tego statementw logicznym znaczeniu formalnym tego słowa. Jest to taki, który zmienia stan jednej lub więcej zmiennych w obliczeniach, umożliwiając złożenie prawdziwej lub fałszywej instrukcji dotyczącej ich wartości.

Wydaje mi się, że zawsze będzie zamieszanie w świecie komputerów i nauki w ogóle, gdy wprowadzana jest nowa terminologia lub słowa, istniejące słowa są „zmieniane” lub użytkownicy nie znają istniejącej, ustalonej lub „właściwej” terminologii w odniesieniu do tego, co opisują


1

Nie jestem do końca zadowolony z żadnej z odpowiedzi tutaj. Spojrzałem na gramatykę dla C ++ (ISO 2008) . Jednak może ze względu na dydaktykę i programowanie odpowiedzi mogą wystarczyć do rozróżnienia tych dwóch elementów (rzeczywistość wygląda jednak na bardziej skomplikowaną).

Instrukcja składa się z zerowej lub większej liczby wyrażeń, ale może też być innymi pojęciami językowymi. Oto formularz Extended Backus Naur dla gramatyki (fragment oświadczenia):

statement:
        labeled-statement
        expression-statement <-- can be zero or more expressions
        compound-statement
        selection-statement
        iteration-statement
        jump-statement
        declaration-statement
        try-block

Widzimy inne pojęcia, które są uważane za instrukcje w C ++.

  • wyrażenie-wyrażenie s jest samo-wyjaśniające się (wyrażenie może składać się z zero lub więcej wyrażeń, przeczytaj gramatykę ostrożnie, to trudne)
  • casena przykład jest instrukcją oznaczoną etykietą
  • oświadczenia wyboruif if/else,case
  • iteracja-statement y są while, do...while,for (...)
  • Oświadczenie jump- y są break, continue, return(może powrócić wyrażenie),goto
  • deklaracja- zestaw to zestaw deklaracji
  • try-block to instrukcja reprezentująca try/catchbloki
  • i może być trochę więcej w gramatyce

To jest fragment pokazujący część wyrażeń:

expression:
        assignment-expression
        expression "," assignment-expression
assignment-expression:
        conditional-expression
        logical-or-expression assignment-operator initializer-clause
        throw-expression
  • wyrażenia są lub zawierają często przypisania
  • wyrażenie warunkowe (dźwięki mylące) odnosi się do użycia operatorów ( +, -, *, /, &, |, &&, ||, ...)
  • wyrażenie ekspresji - co? throwklauzula jest wyrazem zbyt

0

Oświadczenia są gramatycznie kompletnymi zdaniami. Wyrażenia nie są. Na przykład

x = 5

czyta się jako „x dostaje 5.” To jest pełne zdanie. Kod

(x + 5)/9.0

brzmi: „x plus 5 wszystkie podzielone przez 9,0”. To nie jest pełne zdanie. Twierdzenie

while k < 10: 
    print k
    k += 1

to pełne zdanie. Zauważ, że nagłówek pętli nie jest; „zaś k <10” jest klauzulą ​​podrzędną.


whileto wyrażenie to niektóre języki, takie jak Scala. Gramatyka gramatyki z pisaniem na klawiaturze. Zobacz moją odpowiedź .
Shelby Moore III,

Oto pętla while w scala: tutorialspoint.com/scala/scala_while_loop.htm Pętla z predykatem i bez ciała nie jest gramatycznie kompletnym zdaniem. To nie jest pełne wyrażenie. Potrzebujesz ciała, aby wypełnić je jako wyrażenie.
ncmathsadist

A whilez ciałem jest nadal wyrazem w Scali. Może to być również stwierdzenie, jeśli powoduje skutki uboczne, na co pozwala moja mocno oceniona odpowiedź (wyrażenie może być również stwierdzeniem). Moja odpowiedź jest jedyna poprawna. Przepraszamy wszystkim czytelnikom, którzy nie mogą zrozumieć.
Shelby Moore III,

Co masz na myśli pod względem gramatycznym? W języku C (x + 5)/9.0zdecydowanie może być samodzielny jako stwierdzenie. Ponadto, jeśli gramatycznie ukończone, masz na myśli prawidłowy program, C nie zezwala, aby instrukcje były samodzielne jako pojedynczy program.
Akangka

Gramatycznie kompletne: stanowi pełne zdanie.
ncmathsadist

0

Oto podsumowanie jednej z najprostszych odpowiedzi, jakie znalazłem.

pierwotnie odpowiedział Anders Kaseorg

Instrukcja to kompletny wiersz kodu, który wykonuje pewne działania, podczas gdy wyrażenie to dowolna sekcja kodu, której wynikiem jest wartość.

Wyrażenia można łączyć „poziomo” w większe wyrażenia za pomocą operatorów, natomiast wyrażenia można łączyć „pionowo” pisząc jeden po drugim lub za pomocą konstrukcji blokowych.

Każde wyrażenie może być użyte jako instrukcja (której efektem jest ocena wyrażenia i zignorowanie wartości wynikowej), ale większość instrukcji nie może być użyta jako wyrażenie.

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


0

Faktyczna podstawa tych pojęć to:

Wyrażenia : kategoria składniowa, której wystąpienie można ocenić na wartość.

Oświadczenie : kategoria składniowa, której instancja może być zaangażowana w ocenę wyrażenia i wynikowa wartość oceny (jeśli istnieje) nie jest gwarantowana.

Oprócz bardzo początkowego kontekstu FORTRAN z pierwszych dziesięcioleci, obie definicje wyrażeń i stwierdzeń w przyjętej odpowiedzi są oczywiście błędne:

  • Wyrażenia mogą być nieocenionymi operandami. Wartości nigdy nie są z nich tworzone.
    • Podwyrażenia nieprecyzyjnych ocen można zdecydowanie nie docenić.
      • Większość języków podobnych do C ma tak zwane reguły oceny zwarć , które warunkowo pomijają niektóre oceny podwyrażeń, nie zmieniając wyniku końcowego pomimo skutków ubocznych.
    • C i niektóre języki podobne do C mają pojęcie nieocenionego operandu, który może być nawet normalnie zdefiniowany w specyfikacji języka. Takie konstrukcje są wykorzystywane do definitywnego unikania ocen, więc pozostałe informacje kontekstowe (np. Typy lub wymagania dotyczące wyrównania) można rozróżnić statycznie bez zmiany zachowania po tłumaczeniu programu.
      • Na przykład wyrażenie użyte jako operand sizeofoperatora nigdy nie jest oceniane.
  • Instrukcje nie mają nic wspólnego z konstrukcjami liniowymi. Mogą robić coś więcej niż wyrażenia, w zależności od specyfikacji języka.
    • Współczesny Fortran, jako bezpośredni potomek starego FORTRAN, ma koncepcje instrukcji wykonywalnych i instrukcji niewykonalnych .
    • Podobnie C ++ definiuje deklaracje jako podkategorię najwyższego poziomu jednostki tłumaczeniowej. Deklaracja w C ++ jest instrukcją. (Nie jest to prawdą w C.) Istnieją również wyrażenia podobne do instrukcji wykonywalnych Fortrana.
    • Dla porównania z wyrażeniami ważne są tylko instrukcje „wykonywalne”. Ale nie można zignorować faktu, że instrukcje są już uogólnione, aby były konstrukcjami tworzącymi jednostki tłumaczeniowe w tak imperatywnych językach. Jak widać, definicje kategorii są bardzo różne. (Prawdopodobnie) pozostałą tylko wspólną właściwością zachowaną wśród tych języków jest to, że oczekuje się, że instrukcje będą interpretowane w porządku leksykalnym (dla większości użytkowników, od lewej do prawej i od góry do dołu).

(BTW, chcę dodać [potrzebne źródło] do tej odpowiedzi dotyczącej materiałów o C, ponieważ nie pamiętam, czy DMR ma takie opinie. Wydaje się, że nie, w przeciwnym razie nie powinno być żadnych powodów, aby zachować powielanie funkcjonalności w projekcie C : w szczególności operator przecinka vs. wyciągi).

(Poniższe uzasadnienie nie jest bezpośrednią odpowiedzią na pierwotne pytanie, ale uważam za konieczne wyjaśnienie czegoś, na co już tutaj odpowiedziano).

Niemniej jednak wątpliwe jest, abyśmy potrzebowali określonej kategorii „instrukcji” w językach programowania ogólnego przeznaczenia:

  • Nie gwarantuje się, że instrukcje mają więcej możliwości semantycznych niż wyrażenia w zwykłych projektach.
    • Wiele języków już z powodzeniem porzuciło pojęcie wyrażeń, aby uzyskać czyste, schludne i spójne ogólne wzory.
      • W takich językach wyrażenia mogą zrobić wszystko, co mogą zrobić instrukcje w starym stylu: po prostu upuść nieużywane wyniki podczas oceny wyrażeń, albo pozostawiając wyniki jawnie nieokreślone (np. W schemacie R n RS), lub mające specjalną wartość (jako wartość typu jednostki), której nie można uzyskać na podstawie oceny normalnego wyrażenia.
      • Reguły oceny wyrażeń w porządku leksykalnym można zastąpić operatorem jawnej kontroli sekwencji (np. Na beginschemacie) lub cukrem syntaktycznym struktur monadycznych.
      • Reguły porządku leksykalnego innych rodzajów „instrukcji” można wyprowadzić jako rozszerzenia składniowe (na przykład za pomocą makr higienicznych), aby uzyskać podobną funkcjonalność składniową. (I faktycznie może zrobić więcej .)
    • Przeciwnie, stwierdzenia nie mogą mieć takich konwencjonalnych zasad, ponieważ nie opierają się na ocenie: po prostu nie ma tak powszechnego pojęcia „oceny podstacji”. (Nawet jeśli w ogóle, wątpię, aby istniało coś więcej niż kopiowanie i wklejanie z istniejących reguł oceny wyrażeń.)
      • Zazwyczaj instrukcje zachowujące języki również będą miały wyrażenia do wyrażenia obliczeń, a podkategoria instrukcji najwyższego poziomu jest zachowana do oceny wyrażeń dla tej podkategorii. Na przykład C ++ ma tak zwaną wyrażenie-wyrażenie jako podkategorię i wykorzystuje reguły oceny wyrażeń odrzuconych do określenia ogólnych przypadków ocen pełnych wyrażeń w takim kontekście. Niektóre języki, takie jak C #, decydują się na udoskonalenie kontekstów w celu uproszczenia przypadków użycia, ale bardziej nadymają specyfikację.
  • Dla użytkowników języków programowania znaczenie instrukcji może je jeszcze bardziej pomylić.
    • Rozdzielenie reguł wyrażeń i wyrażeń w językach wymaga większego wysiłku w nauce języka.
    • Naiwna interpretacja porządku leksykalnego ukrywa ważniejsze pojęcie: ocenę wyrażenia. (Jest to prawdopodobnie najbardziej problematyczne.)
      • Nawet oceny pełnych wyrażeń w instrukcjach są ograniczone porządkiem leksykalnym, podwyrażenia nie są (koniecznie). Użytkownicy powinni ostatecznie nauczyć się tego oprócz wszelkich zasad powiązanych z instrukcjami. (Zastanów się, jak sprawić, by nowicjusz otrzymał punkt, który ++i + ++inie ma znaczenia w C.)
      • Niektóre języki, takie jak Java i C #, dodatkowo ograniczają kolejność ocen podwyrażeń, aby nie pozwalały na ignorowanie reguł oceny. Może to być jeszcze bardziej problematyczne.
        • Wydaje się, że jest to zbyt zawężone dla użytkowników, którzy nauczyli się już pojęcia oceny wyrażeń. Zachęca także społeczność użytkowników do stosowania niewyraźnego modelu mentalnego projektowania języka.
        • To jeszcze bardziej podrażnia specyfikację języka.
        • Jest szkodliwy dla optymalizacji, ponieważ pomija ekspresję niedeterminizmu w ocenach, zanim zostaną wprowadzone bardziej skomplikowane prymitywy.
      • Kilka języków, takich jak C ++ (szczególnie C ++ 17), określa bardziej subtelne konteksty reguł oceny, jako kompromis powyższych problemów.
        • Bardzo przesadza ze specyfikacją języka.
        • Jest to całkowicie sprzeczne z prostotą dla przeciętnych użytkowników ...

Dlaczego więc oświadczenia? W każdym razie historia już jest bałaganem. Wygląda na to, że większość projektantów języków nie dokonuje ostrożnego wyboru.

Co gorsza, niektórzy entuzjaści systemów typu (którzy nie znają wystarczająco dobrze historii PL) mają pewne nieporozumienia, że ​​systemy typów muszą mieć istotne znaczenie z bardziej istotnymi projektami reguł dotyczących semantyki operacyjnej.

Poważnie, rozumowanie w zależności od rodzaju nie jest tak złe w wielu przypadkach, ale szczególnie nie jest konstruktywne w tym szczególnym. Nawet eksperci mogą to popsuć.

Na przykład ktoś podkreśla charakter maszynopisu jako główny argument przeciwko tradycyjnemu traktowaniu nielimitowanych kontynuacji . Chociaż wniosek jest dość rozsądny, a spostrzeżenia na temat złożonych funkcji są w porządku ( ale nadal są zbyt naiwne dla istoty ), ten argument nie jest trafny , ponieważ całkowicie ignoruje podejście „bocznego kanału” w praktyce, takie jak _Noreturn any_of_returnable_types(w C11) do kodowania Falsum. I ściśle mówiąc, abstrakcyjna maszyna o nieprzewidywalnym stanie nie jest identyczna z „komputerem ulegającym awarii”.


0

W języku programowania zorientowanym na instrukcje blok kodu jest definiowany jako lista instrukcji. Innymi słowy, instrukcja jest częścią składni, którą można umieścić w bloku kodu bez powodowania błędu składniowego.

Wikipedia podobnie definiuje wyrażenie słowne

W programowaniu komputerowym instrukcja jest syntaktyczną jednostką imperatywnego języka programowania, która wyraża pewne działania do wykonania. Program napisany w takim języku składa się z sekwencji jednej lub więcej instrukcji

Zwróć uwagę na to ostatnie zdanie. (chociaż „program” w tym przypadku jest technicznie niepoprawny, ponieważ zarówno C, jak i Java odrzucają program, który nie zawiera żadnych instrukcji).

Wikipedia definiuje wyrażenie wyrażenie jako

Wyrażenie w języku programowania jest jednostką składniową, którą można ocenić w celu ustalenia jego wartości

Jest to jednak fałsz, ponieważ w Kotlinie throw new Exception("")jest wyrażeniem, ale po jego ocenie po prostu zgłasza wyjątek, nigdy nie zwracając żadnej wartości.

W statycznie typowanym języku programowania każde wyrażenie ma swój typ. Ta definicja nie działa jednak w dynamicznie pisanym języku programowania.

Osobiście definiuję wyrażenie jako element składni, który można skomponować za pomocą wywołań operatora lub funkcji w celu uzyskania większego wyrażenia. W rzeczywistości jest to podobne do wyjaśnienia wyrażenia przez Wikipedię:

Jest to kombinacja jednej lub więcej stałych, zmiennych, funkcji i operatorów, które język programowania interpretuje (zgodnie ze swoimi szczególnymi regułami pierwszeństwa i asocjacji) i oblicza w celu wytworzenia („powrotu” w środowisku stanowym) innej wartości

Problem tkwi jednak w języku programowania C, biorąc pod uwagę funkcję execute Coś takiego:

void executeSomething(void){
    return;
}

Czy executeSomething()wyrażenie, czy też jest stwierdzeniem? Według mojej definicji jest to stwierdzenie, ponieważ zgodnie z definicją w gramatyce odniesienia Microsoft w języku C,

Nie możesz użyć (nieistniejącej) wartości wyrażenia typu void w żaden sposób, ani też nie możesz przekonwertować wyrażenia void (poprzez konwersję niejawną lub jawną) na dowolny typ oprócz void

Ale ta sama strona wyraźnie wskazuje, że taka składnia jest wyrażeniem.


-6

Aby poprawić i potwierdzić moją wcześniejszą odpowiedź, w stosownych przypadkach należy wyjaśnić definicje terminów języka programowania na podstawie teorii typów informatyki.

Wyrażenie ma typ inny niż typ Dna, tzn. Ma wartość. Instrukcja ma typ Jednostka lub Dół.

Z tego wynika, że ​​instrukcja może wywoływać jakikolwiek efekt w programie tylko wtedy, gdy tworzy efekt uboczny, ponieważ albo nie może zwrócić wartości, albo zwraca tylko wartość typu Unit, która albo jest nieprzypisywalna (w niektórych językach takie litery C void) lub (takie jak w Scali) mogą być przechowywane w celu opóźnionej oceny instrukcji.

Oczywiście a @pragmalub a /*comment*/nie mają typu i dlatego różnią się od instrukcji. Zatem jedynym rodzajem stwierdzenia, który nie miałby skutków ubocznych, byłby brak operacji. Brak działania jest przydatny tylko jako symbol zastępczy dla przyszłych skutków ubocznych. Wszelkie inne działania wynikające z oświadczenia będą skutkiem ubocznym. Ponownie wskazówka kompilatora, np. @pragma, Nie jest instrukcją, ponieważ nie ma typu.


2
To rozróżnienie nie ma nic wspólnego z rodzajem wyrażeń. Instrukcje zdefiniowane składniowo nie mają żadnych typów w wielu językach. Chociaż nie jestem przeciwny przypisywaniu typu na takich warunkach w teorii, różne sposoby traktowania @pragmalub /*comment*/logicznie niespójne.
FrankHB,

-11

Najbardziej precyzyjnie, oświadczenie musi mieć „efekt uboczny” (czyli być nadrzędny ) i wyrażenie musi mieć na wartość typu (tzn nie dolna typ).

Rodzaj oświadczenia jest typem jednostki, ale ze względu na powstrzymanie twierdzenie jednostka jest fikcja więc powiedzmy, że ten rodzaj dna .


Voidnie jest dokładnie typem dolnym (nie jest podtypem wszystkich możliwych typów). Istnieje w językach, które nie mają całkowicie dźwiękowego systemu . Może to zabrzmieć jak snobistyczna wypowiedź, ale kompletność, taka jak adnotacje dotyczące wariancji, ma kluczowe znaczenie dla pisania rozszerzalnego oprogramowania.

Zobaczmy, co Wikipedia ma do powiedzenia na ten temat.

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

W programowaniu komputerowym instrukcja jest najmniejszym samodzielnym elementem imperatywnego języka programowania, który wyraża pewne działania do wykonania.

Wiele języków (np. C) rozróżnia instrukcje i definicje, przy czym instrukcja zawiera tylko kod wykonywalny i definicję deklarującą identyfikator, podczas gdy wyrażenie ocenia tylko wartość.


5
Oświadczenie nie musi mieć skutków ubocznych. Na przykład w python passznajduje się instrukcja. To jest brak op, i niczego nie ocenia.
Matthew Schinckel,

9
-1 To jest złe. Oświadczenie nie musi mieć skutków ubocznych. Patrz sekcja 1.5 specyfikacji języka C # . Nie tylko nie określa, że ​​stwierdzenia muszą mieć skutki uboczne, ale także wymienia kilka stwierdzeń, które nie mogą mieć skutków ubocznych.
NullUserException

2
@NullUserException Przeczytałem tę sekcję. Instrukcje Deklaracja, Wyrażenie, Wybór, Iteracja i Skok mogą powodować skutki uboczne. Ale jeśli istnieje wyrażenie RT, to nie jest to stwierdzenie. Zdaję sobie sprawę, że specyfikacja utożsamia wyrażenia z wyrażeniami, ale w tym pytaniu pojawiła się różnica między nimi. Więc albo pytanie nie ma odpowiedzi, albo bierzesz specyfikację C # zbyt dosłownie. Najwyżej głosowana odpowiedź próbuje powiedzieć, co zrobiłem. Ale „robi coś” jest bez znaczenia. „efekt uboczny” to znaczący sposób na powiedzenie „robi coś”. Musimy myśleć, a nie tylko regurgitować.
Shelby Moore III,

13
@ShelbyMooreIII Masz rację. Oficjalna dokumentacja jest nieprawidłowa . Marc Gravell i Jon Skeet, którzy są prawdopodobnie najbardziej szanowanymi plakatami C # aktywnymi na SO poza Ericiem Lippertem, są w błędzie . Ja i wszyscy inni, którzy głosowali na ciebie i zostawili komentarze wyjaśniające nasze stanowisko, są w błędzie . Masz rację. Wyraźnie jesteś jedyną osobą, która wie, o czym mówią, ponieważ jesteś o wiele mądrzejszy niż cała reszta SO.
NullUserException

3
Znajomość dokładnej definicji takich pojęć, jak wyrażenie, wyrażenie, rzutowanie, konwersja itp. Nie ma wpływu na 99,999% codziennych zadań programistycznych. Pomyśl o tym . Ponadto: większość ludzi nie dba o Haskell i Scalę.
NullUserException
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.