Jeśli pracujesz z językami imperatywnymi, np. Java, w których króluje "statement" i/lub językami funkcyjnymi, np. Scala lub Clojure, w których prym wiedzie "expression", warto znać różnicę. Przyznaję, że mi to trochę zajęło (zajęcia na studiach jakoś tak wtedy nużyły).
Niby oczywista jest ta różnica, ale nie wszyscy ją wyłapują. U mnie długo trwało zanim zaskoczyło. "expression" zawsze zwraca wartość i jest jej reprezentantem, a "statement" może, ale nie musi i zwykle stosowany jest dla skutków ubocznych, np. przypisanie częściowego wyliczenia do zmiennej poza nim, np. pętla for w Javie.
Od tej chwili usilnie próbuję zapamiętać, że w językach funkcyjnych korzystamy wyłącznie z "wyrażeń", podczas gdy w imperatywnych również i "instrukcji" (patrz Wikipedia w Instrukcja (informatyka) w sekcji Wyrażenia).
I już nie mam problemów ze wskazaniem wyrażenia od instrukcji. A nawet w tłumaczeniu!
Dla zwrócenia uwagi, posłużę się kawałkami kodu w Clojure.
If jest specjalną formą (= wyrażeniem) w Clojure (w przeciwieństwie do Javy) i działa na podobieństwo funkcji, które można przypisywać (aliasować), przekazywać do czy zwracać z funkcji.
user=> ; przypisanie user=> (def if-inside #_=> (if nil "nil jest prawda" "nil nie jest prawda")) #'user/if-inside user=> if-inside "nil nie jest prawda" user=> ; przekazanie do funkcji user=> (defn my-fn [if-stmt] #_=> if-stmt) #'user/my-fn user=> (my-fn if-inside) "nil nie jest prawda" user=> ; zwrocenie z funkcji user=> (defn my-fn-returns-if-stmt [if-stmt] #_=> (fn [] if-stmt)) #'user/my-fn-returns-if-stmt user=> (my-fn-returns-if-stmt if-inside) #<user$my_fn_returns_if_stmt$fn__3525 user$my_fn_returns_if_stmt$fn__3525@2304a962> user=> ((my-fn-returns-if-stmt if-inside)) "nil nie jest prawda"Proste, co?
A może jednak nie? Pytaj, aby było! Mówią, że to podstawy podstaw programowania funkcyjnego i brak zrozumienie fundamentów może negatywnie "promieniować" na dalszą znajomość jego.
Uwaga na stwierdzenie „If jest specjalną formą (= wyrażeniem)” — forma specjalna i wyrażenie to nie to samo więc stawianie znaku równości jest tu niewłaściwe. Poza tym warto może zwrócić uwagę na to, że w Clojure nie każde wyrażenie zwraca wartość. Na przykład następujące nie zwraca: (while true).
OdpowiedzUsuńGrzegorz Balcerek
Dobrze, że o tym wspominasz, bo sam ostatnio się nad tym głowiłem.
Usuń(while) jest makrem i formą, a forma nie musi być wyrażeniem, bo staje się nim, kiedy jest wykonywalna. Tyle teorii. Innymi słowy, wszystko w Clojure jest formą, która po wczytaniu staje się wyrażeniem.
Pewnie niewiele to wyjaśnia, bo więcej powtarzam niż piszę ze zrozumieniem. Pracuję nad tym, aby to zmienić.
Rozszerzając odpowiedź - http://clojure.org/evaluation opisuje proces wykonania sekwencji form i rzuca światło na cały proces wprowadzania poleceń, które są kompilowane i uruchamiane w Clojure.
UsuńWłaśnie brnę przez ten materiał, aby opanować koncept.