Będę szczery: nie rozumiem, co oznacza „użycie składni, a nie semantyki”. Dlatego część tej odpowiedzi dotyczy odpowiedzi Lunaryona , a drugą częścią będzie moja próba odpowiedzi na pierwotne pytanie.
Kiedy słowo „semantyka” używane jest w programowaniu, odnosi się do sposobu, w jaki autor języka zdecydował się interpretować swój język. Zwykle sprowadza się to do zestawu formuł, które przekształcają reguły gramatyczne języka w niektóre inne reguły, o których czytelnik jest znany. Na przykład Plotkin w swojej książce Structural Approach to Operational Semantics używa logicznego języka pochodnego, aby wyjaśnić, na co ocenia składnia abstrakcyjna (co to znaczy uruchomić program). Innymi słowy, jeśli składnia stanowi język programowania na pewnym poziomie, to musi mieć pewną semantykę, w przeciwnym razie jest to ... no cóż, język programowania.
Ale na razie zapomnijmy o formalnych definicjach, w końcu ważne jest, aby zrozumieć intencję. Wygląda więc na to, że lunaryon zachęciłby swoich czytelników do używania makr, gdy program nie ma dodawać nowego znaczenia, a jedynie jakiś skrót. Dla mnie to brzmi dziwnie iw jaskrawym kontraście do faktycznego wykorzystania makr. Poniżej znajdują się przykłady, które wyraźnie tworzą nowe znaczenia:
defun
Znajomi, którzy są istotną częścią języka, nie mogą być opisani tymi samymi terminami, które opisalibyśmy wywołania funkcji.
setf
zasady opisujące działanie funkcji są nieodpowiednie do opisania efektów takiego wyrażenia (setf (aref x y) z)
.
with-output-to-string
zmienia również semantykę kodu wewnątrz makra. Podobnie with-current-buffer
i kilka innych with-
makr.
dotimes
i podobnych nie można opisać w kategoriach funkcji.
ignore-errors
zmienia semantykę zawijanego kodu.
W cl-lib
pakiecie, eieio
pakiecie i kilku innych niemal wszechobecnych bibliotekach używanych w Emacs Lisp znajduje się cała masa makr , które, choć mogą wyglądać jak formy funkcyjne, mają różne interpretacje.
Zatem makra są narzędziem do wprowadzania nowej semantyki do języka. Nie mogę wymyślić alternatywnego sposobu na zrobienie tego (przynajmniej nie w Emacs Lisp).
Kiedy nie używałbym makr:
Gdy nie wprowadzają żadnych nowych konstrukcji, z nową semantyką (tj. Funkcja wykona zadanie równie dobrze).
Gdy jest to po prostu wygoda (tj. Tworzenie makra o nazwie, mvb
które rozwija się, cl-multiple-value-bind
aby go skrócić).
Kiedy oczekuję, że makro ukryje wiele kodu obsługi błędów (jak zauważono, makra są trudne do debugowania).
Gdy zdecydowanie wolę makra niż funkcje:
Gdy pojęcia specyficzne dla domeny są zasłaniane przez wywołania funkcji. Na przykład, jeśli trzeba przekazać ten sam context
argument do zestawu funkcji, które należy wywoływać kolejno, wolałbym zawinąć je w makro, w którym context
argument jest ukryty.
Kiedy ogólny kod w postaci funkcji jest zbyt szczegółowy (konstrukcje iteracji gołej w Emacsie Lisp są zbyt gadatliwe na mój gust i niepotrzebnie narażają programistę na szczegóły implementacji niskiego poziomu).
Ilustracja
Poniżej znajduje się rozwodniona wersja, która ma dać intuicję co do znaczenia semantyki w informatyce.
Załóżmy, że masz niezwykle prosty język programowania z tymi samymi regułami składni:
variable := 1 | 0
operation := +
expression := variable | (expression operation expression)
z tym językiem możemy skonstruować „programów” jak (1+0)+1
lub 0
czy ((0+0))
itd.
Ale dopóki nie podamy reguł semantycznych, te „programy” są bez znaczenia.
Załóżmy, że teraz wyposażamy nasz język w (semantyczne) reguły:
0+0 0+1 1+0 1+1 (exp)
---, ---, ---, ---, -----
0 1+0 1 0 exp
Teraz możemy faktycznie wykonać obliczenia przy użyciu tego języka. Oznacza to, że możemy wziąć reprezentację składniową, zrozumieć ją abstrakcyjnie (innymi słowy, przekształcić ją w składnię abstrakcyjną), a następnie użyć reguł semantycznych do manipulacji tą reprezentacją.
Kiedy mówimy o rodzinie języków Lisp, podstawowymi semantycznymi regułami oceny funkcji są z grubsza zasady rachunku lambda:
(f x) (lambda x y) x
-----, ------------, ---
fx ^x.y x
Mechanizmy cytowania i makroekspansji są również znane jako narzędzia metaprogramowania, tzn. Pozwalają mówić o programie, a nie tylko programować. Osiągają to poprzez tworzenie nowej semantyki przy użyciu „warstwy meta”. Przykładem takiego prostego makra jest:
(a . b)
-------
(cons a b)
To nie jest makro w Emacsie Lisp, ale mogło być. Wybrałem tylko dla uproszczenia. Zauważ, że żadna z reguł semantycznych zdefiniowanych powyżej nie miałaby zastosowania w tym przypadku, ponieważ najbliższy kandydat (f x)
interpretuje f
jako funkcję, choć a
niekoniecznie jest funkcją.