Uczę się makr Clojure i zastanawiam się, dlaczego nie możemy używać prostych funkcji do metaprogramowania.Clojure, może makra zrobić coś, czego nie da się zrobić przy pomocy funkcji
O ile wiem, różnica między makro i funkcji jest to, że argumenty makra nie są oceniane, ale przekazywane jako struktur danych i symboli, ponieważ są one, podczas gdy wartości zwracanej jest oceniano (w miejscu, w którym makro jest nazywany). Makro działa jako pośrednik między czytnikiem a oceniającym, przekształcając formularz w sposób arbitralny przed dokonaniem oceny. Wewnętrznie mogą używać wszystkich funkcji językowych, w tym funkcji, specjalnych formularzy, literałów, rekursji, innych makr itp.
Funkcje są odwrotne. Argumenty są sprawdzane przed wywołaniem, zwracana wartość nie jest po powrocie. Ale lustrzana natura makr i funkcji sprawia, że zastanawiam się, czy nie moglibyśmy równie dobrze użyć makr funkcji, cytując ich argumenty (formę), przekształcając formę, oceniając ją wewnątrz funkcji, ostatecznie zwracając jej wartość. Czy to logicznie nie dałoby takiego samego rezultatu? Oczywiście byłoby to niewygodne, ale teoretycznie, jest odpowiednikiem dla każdego możliwego makro?
Oto prosty infix makro
(defmacro infix
"translate infix notation to clojure form"
[form]
(list (second form) (first form) (last form)))
(infix (6 + 6)) ;-> 12
Tutaj jest sama logika użyciu funkcji
(defn infix-fn
"infix using a function"
[form]
((eval (second form)) (eval (first form)) (eval (last form))))
(infix-fn '(6 + 6)) ;-> 12
Teraz jest to postrzeganie uogólnić do wszystkich sytuacji, czy istnieją pewne przypadki narożne gdzie makro mogłem” t być przesadzone? Na koniec, czy makra są po prostu syntaktycznym cukrem nad wywołaniem funkcji?
Zwróć uwagę, że makra są rekursywnie rozwijane w czasie makro wyskalowania (zwykle przed kompilacją), a nie podczas wykonywania. Skompilowany kod będzie wyglądał tak, jakbyś pisał ekspansję ręcznie, więc nie ma dla niego kary za wydajność. Pamiętaj również, że 'eval' ocenia formularz w pustym środowisku leksykalnym. '(niech [x 10] (infix-fn '(x + 6)))' => 'CompilerException ... Nie można rozwiązać symbolu: x' – jkiiski
To są dobre punkty Nie myślałem o –