LINUX.ORG.RU

Правильная реализация макроса в Сommon Lisp


0

0

Такая задачка. Есть список вида

(("name1" "value1") ("name2" "value2") ... ("name_n" "value_n"))

"name_i" и "value_i" - строковые элементы, "name_i" - некоторый уникальный в пределах списка идентификатор (ключ), "value_i" - значение которое ассоциировано с ключом. n - достаточно велико

Нужен макрос вида

(with-values ((var-i "name_i")*) lst body*)

где lst - исходный список, var-i переменные в которые записывается значения "value_i" ассоциированные с "name_i". body - фрагмент программы из которого можно обращаться к переменным var-i.

Например

(let ((lst '(("name" "Ivan Pupkin") ("age" "21") ("sex" "male")))) (with-values ((name "name") (age "age")) (print name) (print age)))

Должно напечатать

"Ivan Pupkin" "21"

Мой кривой вариант:

(defmacro with-values ( decls ast body )

(let ((let-body nil) (when-body nil))

(dolist (decl decls) (push `(,(car decl) nil) let-body) (push `(when (string= (car l) ,(cadr decl)) (setq ,(car decl) (cadr l))) when-body))

(setq when-body (append '(progn) when-body))

(print `(let ,let-body (dolist (l ,ast) ,when-body) ,body))))

Внимание вопрос: А как это реализовать правильно ?

PS понимаю, что хеши для таких задач лучше подходят, но менять исходную структуру данных не могу :)

★★

Тфу ты. 

Такая задачка. Есть список вида

(("name1" "value1") ("name2" "value2") ... ("name_n" "value_n"))

"name_i" и "value_i" - строковые элементы, 
"name_i" - некоторый уникальный в пределах списка идентификатор (ключ), 
"value_i" - значение которое ассоциировано с ключом. 
n - достаточно велико

Нужен макрос вида

(with-values ((var-i "name_i")*) lst body*)

где 
lst - исходный список, 
var-i переменные в которые записывается значения "value_i"
 ассоциированные с "name_i" 
body - фрагмент программы из которого можно обращаться к переменным var-i.


Например

(let ((lst '(("name" "Ivan Pupkin") ("age" "21") ("sex" "male"))))     
     (with-values ((name "name")
                   (age "age")) 
         (print name) 
         (print age)))

Должно напечатать

"Ivan Pupkin" 
"21"

Мой кривой вариант:


(defmacro with-values ( decls ast body ) 

  (let ((let-body  nil)
	(when-body nil))

    (dolist (decl decls)
      (push `(,(car decl) nil) let-body)
      (push `(when (string= (car l) ,(cadr decl)) (setq ,(car decl) (cadr l))) when-body))

    (setq when-body (append '(progn) when-body))

    (print `(let ,let-body (dolist (l ,ast) ,when-body) ,body))))



Внимание вопрос: А как это реализовать правильно ?

PS понимаю, что хеши для таких задач лучше подходят, но менять 
исходную структуру данных не могу :) 

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

Чёто я тя не пойму совсем :(. Ты хотиш чёбы макрос вызывал тело для каждой подходящей найденной пары (key, value) или сначала собрал имеющиеся, а потом уж вызвал с ними? Чё делать если не найдутся или будет несколько?

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

Ну лови.

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defvar *decls* '(("name" "Ivan Pupkin") ("age" "21") ("sex" "male"))))

(defmacro with-values (decls vals &body body) 
  (let ((let-vars  nil))
    (dolist (val (symbol-value vals))
      (dolist (decl decls)
	(when (string= (cadr decl) (car val))
	  (push (list (car decl) (cadr val)) let-vars))))
    `(let ,let-vars
       (progn ,@body))))

(defun test ()
  (with-values ((name "name") (age "age")) *decls*
    (print name) 
    (print age)))

Краткая идея такая: пробегаем по списку заданых пар (vals) и для каждого значения name_i 
проверяем есть ли оно в описании переменных (decls).
Совпавшие значения загоняем в список let-vars.

eval-when используется для того, чтобы определить *decls* еше на этапе компиляции. 
Потом в макросе мы добираемся до значении этой переменной через symbol-value.

А хеши для этой задачи без надобности, так как макросы будут развернуты еще 
на этапе компиляции и хеши ускорят только компиляцию, но не выполнение.

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

А если let заменить на symbol-macrolet (не в лоб - дописать чуть-чуть надо :) то можно будет ещё и менять данные

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

Да уж. Вот что значит писать в форум в полвторого ночи :)

Требуется 2-е. Несколько вариантов быть не может, "name_i" - уникальное значение

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

Забыл описать. Этот *decls* в общем случае определяется в рантайме.

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