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?
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?
Odpowiedzi:
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ż callfunc
moż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.
callfunc(x = 2);
przechodzi x
na callfunc
nie 2
. Jeśli x
jest zmiennoprzecinkowe, callfunc(float)
zostanie wywołane, a nie callfunc(int)
. A w C ++, jeśli przejdziesz x=y
do func
i func
odniesiesz odniesienie i je zmienisz , to się zmieni x
, a nie y
.
where
klauzula w haskell jest uważana za wyrażenie, a nie stwierdzenie. learnyouahaskell.com/syntax-in-functions#where
where
rzeczywistości jest częścią deklaracji funkcji, a nie wyrażenia lub instrukcji.
Zauważ, że w C „=” jest w rzeczywistości operatorem, który wykonuje dwie rzeczy:
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 ';'
;
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.
foo.voidFunc(1);
jest wyrażeniem o pustej wartości. while
i if
są oświadczeniami.
return
jest to uważane za podstację.
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.
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.
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ą.
Void
nie jest typem dolnym. Zobacz moją odpowiedź .
null
)? Czy nie void
byłby bardziej podobny do typu jednostki (ale z jedną wartością niedostępną)?
void
jest to typ zwracany przez funkcję, która nigdy nie zwraca (np. Funkcja, która throw
jest błędem), jest to typ dolny . W przeciwnym razie void
jest 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
.
null
Wartość jest naprawdę pseudovalue oznaczający, że odwołanie odnosi się do czegoś, co nie istnieje.
Po prostu: wyrażenie zwraca wartość, a instrukcja nie.
{}
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.
{}
jest zdefiniowany jako instrukcja w specyfikacji języka C #.
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:
OpenADoor(), FlushTheToilet()
lub TwiddleYourThumbs()
zwróci jakąś przyziemną wartość, taką jak OK, Gotowe lub Sukces.(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
)
Instrukcja jest szczególnym przypadkiem wyrażenia, z void
typem. 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ą TResult
bycia 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 void
i łączącym je w jedno wyrażenie typu void
.
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)
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 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.
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;}
:)
Wolę znaczenie tego statement
w 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ą
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 ++.
case
na przykład jest instrukcją oznaczoną etykietąif
if/else
,case
while
, do...while
,for (...)
break
, continue
, return
(może powrócić wyrażenie),goto
try/catch
blokiTo 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
+
, -
, *
, /
, &
, |
, &&
, ||
, ...)throw
klauzula jest wyrazem zbytOś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ą.
while
to wyrażenie to niektóre języki, takie jak Scala. Gramatyka gramatyki z pisaniem na klawiaturze. Zobacz moją odpowiedź .
while
z 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ć.
(x + 5)/9.0
zdecydowanie 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.
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.
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:
sizeof
operatora nigdy nie jest oceniane.(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:
begin
schemacie) lub cukrem syntaktycznym struktur monadycznych.++i + ++i
nie ma znaczenia w C.)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”.
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.
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 @pragma
lub 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.
@pragma
lub /*comment*/
logicznie niespójne.
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 .
Void
nie 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ść.
pass
znajduje się instrukcja. To jest brak op, i niczego nie ocenia.