Создание подобных функций с помощью макроса Лиспа

В своей работе я пытаюсь использовать макросы в Common Lisp и у меня есть несколько вопросов. у меня две функции

(defun when-tagflag ()
  (when (= tagflag 1)
   (setf tagflag 0)
   (push tagbuf taglist)
   (setf tagbuf "")))


 (defun when-attrflag ()
  (when (= attrflag 1)
   (setf attrflag 0)
   (push attrbuf attrlist)
   (setf attrbuf "")))

Очень похожие функции. После нескольких часов экспериментов у меня получился вот такой макрос

defmacro when-flag (name)
 (let ((flag (read-from-string (concatenate 'string (string name) "flag")))
       (lst (read-from-string (concatenate 'string (string name) "list")))
       (buf (read-from-string (concatenate 'string (string name) "buf"))))
 `(when (= ,flag 1)
   (setf ,flag 0)
   (push ,buf ,lst)
   (setf ,buf ""))))


 > (pprint (macroexpand-1 '(when-flag "tag")))
 > (WHEN (= TAGFLAG 1) (SETF TAGFLAG 0) (PUSH TAGBUF TAGLIST) (SETF TAGBUF ""))

Внутри флага when я использую конкатенацию строки и чтение из строки, но я думаю, что мой метод не канонический. Есть ли более подходящие подходы к решению такой проблемы?

P.S. Это решение не работает для меня Можете ли вы создать интерактивный функции в макросе Emacs Lisp?


person A.M. Sultanov    schedule 19.09.2014    source источник
comment
(setf attrlist (push attrbuf attrlist)) это всего лишь (push attrbuf attrlist).   -  person Rainer Joswig    schedule 20.09.2014
comment
@RainerJoswig спасибо за совет :) я новичок в lisp)   -  person A.M. Sultanov    schedule 20.09.2014
comment
Я изменил тег: язык называется Common Lisp, а не Clisp.   -  person Rainer Joswig    schedule 20.09.2014
comment
Как к вашему сведению, для меня это тревожный сигнал. Вы используете несколько числовых флагов достаточно точно, чтобы вам нужен макрос, подобный этому, и вы, похоже, мутируете как минимум четыре глобальные переменные. Если бы у меня был такой код, я бы очень внимательно посмотрел на него, чтобы увидеть, нет ли лучшего способа выразить мое намерение. Попробуйте отправить его на CR, когда закончите.   -  person Inaimathi    schedule 20.09.2014
comment
@Inaimathi Спасибо за ваш комментарий. Я согласен, что это неправильно. Все когда-функции являются частью замыкания. Но я не добавляю это в свой вопрос. Это прототип для некоторых задач, и когда я думал о рефакторинге, я увидел это сходство между этими функциями. Я подумал: могут ли макросы помочь мне в этой задаче?   -  person A.M. Sultanov    schedule 20.09.2014
comment
Проблема, похоже, в том, что вы закодировали параметры в именах функций. Хотя вы можете сделать это менее болезненным, ответив на этот вопрос, реальное решение состоит в том, чтобы поместить ваши флаги, буферы и списки в структуру данных, например. г. хэш-таблица. Это могут быть три хеш-таблицы или одна хеш-таблица, ссылающаяся на объекты, содержащие три компонента имени.   -  person Svante    schedule 20.09.2014


Ответы (1)


Имена символов в Common Lisp по умолчанию имеют внутренний верхний регистр.

CL-USER 10 > (intern (concatenate 'string "TAG" "FLAG") "CL-USER")
TAGFLAG
:INTERNAL

CL-USER 11 > (intern (format nil "~:@(~AFLAG~)" "TAG") "CL-USER")
TAGFLAG
:INTERNAL

Пример:

(defmacro when-flag (prefix &key (package-name "CL-USER"))
  (flet ((create-symbol (suffix)
           (intern (format nil "~:@(~A~A~)" prefix suffix)
                   package-name)))
    (let ((flag-sym (create-symbol "FLAG"))
          (list-sym (create-symbol "LIST"))
          (buf-sym  (create-symbol "BUF")))
      `(when (= ,flag-sym 1)
         (setf ,flag-sym 0)
         (push ,buf-sym ,list-sym)
         (setf ,buf-sym "")))))
person Rainer Joswig    schedule 19.09.2014
comment
Спасибо) Я попробовал символы и функцию стажера, и теперь я нахожу, что было не так. Я использовал стажер со строкой в ​​нижнем регистре. А как насчет чтения из строки - это правильное решение? - person A.M. Sultanov; 20.09.2014