Регистрация | Войти
Lisp — программируемый язык программирования
RSS
Непонятки с подстановкой макросов
civil696 - 21.06.2010 01:45, Сообщений - 1
Есть два вот таких макроса:
(defmacro cl-cond [& clayses]
`(cond ~@(reduce concat clayses)))

(defmacro .rule [rule]
(list (list 'allowed? 'state 'current-symbol rule)
(list 'do (list (list 'action rule) 'current-symbol)
(list 'recur (list 'rest 'word) (list 'next-state rule)))))
Пытаюсь определить с помощью них функцию и получаю ошибку "Can't take value of a macro: #'user/.rule"
user=> (defn mfsm [word1]       
(loop [word (seq word1) state 'begin]
(let [current-symbol (first word)]
(cl-cond
(.rule vowel-rule)
(.rule consonant-rule)
((empty? word) 'ok)
(:else 'fail)))))
java.lang.Exception: Can't take value of a macro: #'user/.rule (NO_SOURCE_FILE:452
При этом, если просто скопипастить результат (macroexpand '(.rule vowel-rule)) и (macroexpand '(.rule consonant-rule)) на место (.rule vowel-rule) и (.rule consonant-rule) функция вполне корректно определяется.

Никак не пойму в чём может быть проблема и как это правильно дебажить.
[#]
Хм. Я дурак.
Почему-то был свято уверен, что сначала раскроются вызовы (.rule some-rule), а уже потом будет раскрываться (cl-cond ...). Разумеется на самом деле всё с точностью да наоборот, сначала раскрывался (cl-cond ...), превращая
(cl-cond
(.rule vowel-rule)
(.rule consonant-rule)
((empty? word) 'ok)
(:else 'fail))
В
(cond
.rule vowel-rule
.rule consonant-rule
(empty? word) 'ok
:else 'fail)
В результате чего при попытке скармливания .rule if'у в качестве условия и получал "Can't take value of a macro: #'user/.rule" =_=

В конечном счёте не придумал ничего лучше кроме как переписать всё в виде:
(defmacro rule-cond [& clayses]
`(cond ~@(loop [cond-clayses clayses cond-body '()]
(if (empty? cond-clayses) cond-body
(let [clayse (first cond-clayses)]
(if (and (sequential? clayse) (= (first clayse) :rule))
(let [arule (second clayse)]
(recur (rest cond-clayses)
(concat cond-body (list (list 'test-rule arule)
(list 'apply-rule arule)))))
(recur (rest cond-clayses) (concat cond-body (list clayse)))))))))

(defmacro apply-rule [arule]
(list 'do (list (list 'action arule) 'current-symbol)
(list 'recur (list 'rest 'word) (list 'next-state arule))))

(defmacro test-rule [arule]
(list 'allowed? 'state 'current-symbol arule))
и использовать (rule-cond (:rule some-rule)) вместо (cl-cond (.rule some-rule))

civil696 - 21.06.2010 19:09
@2009-2013 lisper.ru