LINUX.ORG.RU

Lisp Macro


0

0

Возникло несколько вопросов по Macro:
1. Первый вопрос навеян топиком "(Lisp) макросы в функционалах", а 
именно насторожила фраза: "Макры во время компиляции выполняются, а
не во время исполнения". Я как раз макры сейчас тока изучаю, я понял
так, что Macro на этапе компиляции расширяется, а выполняется, когда
выполняется ф-ция, в которую он входит, а если не входит ? (сам по
себе). Поэтому просьба к гуру, растусуйте на примере: Например,
(defmacro plus1 (x) `(+ 1 ,x)). Пусть этот макр входит в тело ф-ции
(defun blabla (a b c )
.....
(plus1(b))
...)
Я так понимаю, что при компиляции ф-ции макр расширится, но не 
выполнится, т.к. b на этапе комп. ещё не известен. А еслиб было тоже
самое, но (plus1(5)), макр вернул бы 6 при комп-ии ? А если макр
отдельный, т.е. не входит в ф-ции. тогда как с аргументами ? Явно
задавать надо ? В общем объясните плз.

2. Как с помощью Macro замутить FSM ? Т.е. что предлагают Lisp Macro
взамен C'ым switch/case. Я так понял Macro уже являются генераторами
кода на уровне комп-ии, так что должно бать достаточно просто. Если
можно, простейший примерчик и вообще кошерный Lisp'овый подход к этому вопросу.
anonymous

Взамен С-шным switch/case есть case. А если хочешь больше - то макры тебе дают возможность реализовать то, что ты хочешь

Begemoth ★★★★★
()
Ответ на: комментарий от Begemoth

> А если хочешь больше - то макры тебе дают возможность реализовать то, что ты хочешь

Я вообщето на счёт этого и спрашивал. Еслиб знал, то не спрашивал бы...

anonymous
()

Как я понял, макросы вычисляются в 2 этапа:
1) расширение макроса, конструируется тело макроса с переданными фактическими параметрами
2) полученное расширение вычисляется.
При этом макросы не вычисляют свои аргументы на 1-м этапе, поэтому (в отл. от функций) не возникает проблем с динамическими переменными аргументами, имена которых совпадают с формальными аргументами макроса.

seiken ★★★★★
()

Во что превращается макрос после расширения можно посмотреть с помощью macroexpand, например (macroexpand '(<macro-name> <x1> <x2> ...))

seiken ★★★★★
()
Ответ на: комментарий от seiken

> расширение макроса, конструируется тело макроса с переданными фактическими параметрами

Так, а если переданные параметры не определены на этапе комп-ии, то после расширения они остаются переменными ?

> полученное расширение вычисляется

Расширение вычисляется при выполнении ф-ции, в которую, например, входил макрос ?

anonymous
()
Ответ на: комментарий от anonymous

> Так, а если переданные параметры не определены на этапе комп-ии, то после расширения они остаются переменными ?

На этапе компиляции выполняется макрос (этот процесс называют расширением или expanding, только чтобы не путать с выполнением получаемого кода), и результатом выполнения макроса является код. Переданные параметры подставляются в код. В твоём примере (plus 5) сгенерит код (+ 1 5) а (plus b) - код (+ 1 b). Его выполнение будет на этапе выполнения, если конечно не вмешается оптимизатор и не вычислит константное (+ 1 5). При желании можно сделать (defmacro plus-const (x) (+ 1 x)), он будет генерить только константы, а если в качестве аргумента подставить неконстанту - грязно выругается. Или (defmacro plus-const (x) (+ 1 (eval x))) - сюда уже можно в качестве аргумента давать вычислимые на этапе компиляции выражения. Результатом его выполнения будет также код, состоящий из числовой константы.

bugmaker ★★★★☆
()

> Как с помощью Macro замутить FSM ? Т.е. что предлагают Lisp Macro взамен C'ым switch/case.

Есть макрос cond, я думаю ты легко сможеш найти и посмотреть ево исходники.

bugmaker ★★★★☆
()
Ответ на: комментарий от bugmaker

Немного не понял. Ты говоришь, что мой макр
(defmacro plus1 (x) `(+ 1 ,x))
генерить (+ 1 5) (если передаю константу) и (+ 1 b) (если b -
переменная), т.е. b не известна на этапе комп-ии. А твой
(defmacro plus-const (x) (+ 1 x)) (а чем он от моего отличается ?)
будет генерить тока константы, т.е. правильно ли я понял, что ему
на вход надо давать тока константы, известные на этапе комп-ии ?
Или константа имеется ввиду любая числовая переменная - НЕ
выражение ?

anonymous
()
Ответ на: комментарий от anonymous

> Ты говоришь, что мой макр (defmacro plus1 (x) `(+ 1 ,x)) генерить (+ 1 5) (если передаю константу) и (+ 1 b) (если b - переменная), т.е. b не известна на этапе комп-ии.

Всё правильно.

> А твой (defmacro plus-const (x) (+ 1 x)) будет генерить тока константы

да, ибо сложение будет происходить в момент расширения макроса и будет вернуто значение - результат сложения, числовая константа. Воспользуйся macroexpand, как тебе советовали, чтобы посмотреть результат.

> (а чем он от моего отличается ?)

` препятствует выполнению кода в списке в твоём случае, поэтому результат выполнения твоего макроса - список. Макрос (defmacro plus (x) (list '+ 1 x)) будет полностью аналогичен твоему. В нём более явно видно что возвращается список, но запись несколько длиннее, поэтому такой записью не пользуются. В моём возвращаемое значение - результат выполнения (+ 1 х), ибо ` не препятствует выполнению на момент расширения в нём.

> Или константа имеется ввиду любая числовая переменная - НЕ выражение ?

Да, (defmacro plus-const (x) (+ 1 x)) сможет обработать только аргументы в виде числовых констант, не выражений. Потому что при вызове макроса будет вычислено значение аргумента х. Если оно будет выражением - оно будет списком, например (plus-const (+ 1 2)) будет пытаться сложить 1 с списком (list + 1 2), а со списком складывать нельзя. Поэтому ошибка возникнет ещё на этапе расширения макроса, при компиляции. Вариант с eval вычислит сперва значение x, которое список, потом значение выражения, представленного этим списком, и потом продолжится выполнение расширения макроса.

bugmaker ★★★★☆
()

Возник вопрос поведения глобальных переменных в макро:

(defvar *A* (list 0 1 2))
(defvar *B* (list 0 1 2))
(defvar *AB* (list *A* *B*))

(defparameter *A1* (list 0 1 2))
(defparameter *B1* (list 0 1 2))
(defparameter *AB1* (list *A1* *B1))

(defmacro my_macro (lala)
   (setf a (first (eval lala))
         b (rest  (eval lala)))
   ......
     (my_macro b)...)
Ну примерно так.

(my_macro *AB1*)
Выдаётся ошибка, что *B* не определена.
(my_macro *AB*)
Всё хорошо.

Почему так происходит ? Разве у defvar и defparameter разные
области видимости ?

        

anonymous
()
Ответ на: комментарий от anonymous

Одинаковые, видимо гдето очепятка. Например (defparameter *AB1* (list *A1* *B1)) - *B1 вместо *B1*, если это копипасть кода.

bugmaker ★★★★☆
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.