Създаване на подобни функции с помощта на Lisp макрос

В работата си се опитвам да използвам макроси в 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-flag използвам concatenate string и read-from-string, но мисля, че моят метод не е каноничен. Има ли по-подходящи подходи за решаване на подобен проблем?

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
Благодаря ви) Опитах символи и стажантска функция и сега открих какво не е наред. Използвах intern с низ с малки букви. А какво ще кажете за подхода за четене от низ - това е правилното решение? - person A.M. Sultanov; 20.09.2014