Najbardziej użyteczna intuicja, moim zdaniem, wynika ze zrozumienia celu danego operatora/Var. Dobrze zaprojektowane makra po prostu nie mogą być napisane jako funkcje i nadal oferują tę samą funkcjonalność z tą samą składnią, ponieważ gdyby mogły, byłyby napisane jako funkcje (patrz "dobrze zaprojektowana" część powyżej!). Tak więc, jeśli masz do czynienia z konstruktem, który nie może być normalną funkcją, to wiesz, że tak nie jest; inaczej jest prawdopodobne.
Ponadto, zwykłe sposoby poznawania VAR wyeksportowanych przez bibliotekę informują, czy masz do czynienia z makrem lub funkcją z góry. To prawda, że doc
((doc foo)
mówi, że foo
jest makrem w górnej części jego wyjścia, jeśli tak jest rzeczywiście), source
(ponieważ daje ci cały kod) i M-. (przejdź do definicji w Emacsie z nrepl.el lub swank-clojure; M-, przeskakuje z powrotem). Można oczekiwać, że dokumentacja będzie zawierała wzmiankę o makrze, a co nie (oprócz tego, że niekoniecznie jest to prawda w przypadku docstrukcji, ponieważ wszystkie zwykłe sposoby uzyskiwania dostępu do dokumentacji docstringa już informują, czy masz do czynienia z makrem, jak wyjaśniono powyżej).
Jeśli prześladujesz kodeks z zamiarem sformułowania przybliżonej wiedzy na temat tego, co prawdopodobnie robi przy założeniu, że różni operatorzy wykonują funkcje sugerowane przez ich nazwy, wtedy (1) nazwy są sugestywne wystarczy, abyś zorientował się, co jest zamierzone przez kod, więc nie musisz nawet przejmować się tym, którzy operatorzy są makrami, lub (2) nazwy nie są wystarczająco sugestywne, więc musisz zanurkować w dokumentach lub źródło dla niektórych operatorów, a następnie pierwszą rzeczą, którą się dowiadujesz, jest to, które z nich są zarejestrowane jako makra.
Wreszcie, nie ma jednego stylu nazewnictwa dla makr, chociaż istnieją pewne konwencje specyficzne dla konkretnych przypadków użycia. Na przykład konstrukcje w stylu with-foo
wydają się być makrami wygody, których celem jest uproszczenie obsługi zasobów typu foo
; dofoo
-style to zazwyczaj makra, które pobierają wyrazy do wykonania (ile razy iz jakim dodatkowym kontekstem zależy od makra, najbardziej podstawowy członek tej rodziny, do
, jest w rzeczywistości specjalną formą, a nie makro); deffoo
Konstrukcje w stylu wprowadzają nowe warianty lub jednostki podobne do typu.
Warto zauważyć, że podobne wzory są czasami łamane. Na przykład, większość konstruktów gwintujących (->
& Co.) to makra, ale xml->
z clojure.data.zip.xml
jest funkcją. Ma to sens, gdy weźmie się pod uwagę dostarczoną funkcjonalność, która doprowadza nas do punktu, w którym operator jest najbardziej użytecznym źródłem intuicji.
Mogą istnieć pewne wyjątki od tej reguły. Można oczekiwać, że zostaną udokumentowane. Niektóre projekty oczywiście nie są udokumentowane (lub bardzo blisko); tutaj problem znika całkowicie, ponieważ i tak trzeba iść do źródła, żeby zrozumieć sens rzeczy.
Świetne pytanie. Nie sądzę, żeby można było zobaczyć różnicę tylko patrząc. Jako początkujący mówimy, że składnia jest prosta, wszystko jest (fn args), więc pytasz dlaczego nie (zastosować lub zbić)? A dlaczego nie (map quote coll)? Och, to makra (lub specjalne formy). Po prostu nauczysz się odgadywać, która jest która. – Hendekagon
hehe: (fn? +) True (fn? ->) Nie można wziąć wartości makra! I nie ma makra? lub specjalny formularz? Ale, (: makro (meta # '->)) true – Hendekagon
@ Hendekagon: To jest coś, czego uczy się z doświadczeniem, ale to nie jest po prostu * zgadywanie *, że się uczy, ale raczej * domyśla się * odgadywania * (często z (blisko) pewność). Biorąc na przykład '(map quote coll)', 'quote' nie może być funkcją z powodu fundamentalnych właściwości języka, a w każdym przypadku' (map quote coll) 'jest wywołaniem funkcji, które odbiera' coll' post ewaluacja, więc nie jest jasne, co jest zamierzone (chociaż '(map # (list 'quote' quote%) ...)' może być całkiem przydatne w definicji makra, o ile '...' jest kolekcją, której makro ma dostęp do). –