Множественный макрос defparameter в Lisp?

Я попытался написать макрос defparameter для произвольного количества переменных, начиная с рабочего кода для одной переменной:

(defmacro defpar (name initial-value )                                                  
 `(progn (declaim (special ,name))                                                    
        (setf (symbol-value ',name) ,initial-value)                                  
         ',name)

Вот модификация

(defmacro defpar (&rest rest)
  (let ((i  (gensym)))
    `(let (,i)
;;     (declaim (special ,rest))
       (dotimes (,i  (/ (length ',rest) 2))
         (progn
           (print (list ,i ',rest))
           (setf (symbol-value ',(pop rest)) ',(pop rest))
           )
         ))))

Сейчас:

(defpar S1 1)                                                                            
(print `("S1 = " ,S1))

дает

(0 (S1 1)) 
("S1 = " 1)

Все в порядке: S1 определен и равен 1.

и для двух аргументов

(defpar S1 1 S2 2)                                                                    
(print `("S1 = " ,S1  " S2 = " ,S2 )) 

дает

(0 (*S1* 1 *S2* 2))
(1 (*S1* 1 *S2* 2))
....  The variable *S2* is unbound.   

Как я проверил, список отдыха на новой итерации цикла тот же, но мне не удалось его обновить. И я пропустил специальное заявление. (declaim (special, rest)) возникает ошибка в SBCL. Дайте мне знать, если это важно.

Пожалуйста, помогите мне. Может быть, это уже сделано, как в setf?

Мой ответ не работает, если макрос вызывается следующим образом: (defpar-multiple x (+ 1 2)) потому что мой ответ не оценивает (+ 1 2), тогда как если вы вызовете (defparameter x (+1 2)), то x будет установлено в 3.

7stud 03.04.2024 21:00

Я бы назвал это defparameters

coredump 04.04.2024 13:33
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
102
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Не хорошо! Смотрите комментарии.

Это работает для меня:

(defmacro defpar-multiple (&rest varname-val-list)
  `(loop for (varname val) on ',varname-val-list by #'cddr
         collect varname
         do
            ;;(format t "~a = ~a~%" varname val)
            (setf (symbol-value varname) val)))     
           

В ответе:

CL-USER> (defpar-multiple aaa 2 bbb 3)

Это расширяется до:

(loop for (varname val) on '(aaa 2 bbb 3) by #'cddr
      collect varname
      do (setf (symbol-value varname) val))

И оцениваю:

CL-USER> aaa
; Debugger entered on #<UNBOUND-VARIABLE AAA {700756DAD3}>

[1] CL-USER> bbb
; Debugger entered on #<UNBOUND-VARIABLE BBB {70079BB643}>

CL-USER> (defpar-multiple aaa 2 bbb 3)
(AAA BBB)

CL-USER> aaa
2 (2 bits, #x2, #o2, #b10)

CL-USER> bbb
3 (2 bits, #x3, #o3, #b11)

CL-USER> 

Я не уверен, почему я должен писать:

(setf (symbol-value varname) val)

вместо:

(setf varname val)

но последний не сохраняется во время компиляции.

Отредактированный код:

(defmacro defpar-multiple (&rest varname-val-list)
  `(loop for (varname val) on ',varname-val-list by #'cddr
         for evaled-val = (eval val)
         collect varname
         do  ;;(format t "~a = ~a~%" varname evaled-val)
             (setf (symbol-value varname) evaled-val)))

Затем

CL-USER> (defpar-multiple att 0 gtt (+ 1 4))

расширяется до:

(loop for (varname val) on '(att 0 gtt (+ 1 4)) by #'cddr
      for evaled-val = (eval val)
      collect varname
      do (setf (symbol-value varname) evaled-val))

Оценка:

CL-USER> att
; Debugger entered on #<UNBOUND-VARIABLE ATT {7007340F13}>

CL-USER> gtt
; Debugger entered on #<UNBOUND-VARIABLE GTT {700779AAF3}>

CL-USER> (defpar-multiple att 0 gtt (+ 1 4))
(ATT GTT)

CL-USER> att
0 (0 bits, #x0, #o0, #b0)

CL-USER> gtt
5 (3 bits, #x5, #o5, #b101)

CL-USER> 
(defpar-multiple a (+ 1 2)) -> А = (+ 1 2)
Rainer Joswig 03.04.2024 19:44
(setf varname val) присваивает переменной varname значение переменной var. Вы хотите, чтобы?
Rainer Joswig 03.04.2024 19:46

@RainerJoswig, нет! Редактирую свой ответ, чтобы оператор мог изменить галочку на вашем ответе.

7stud 03.04.2024 20:56

@RainerJoswig, Могу ли я просто добавить (eval val), чтобы вместо установки переменной (+ 1 4) было установлено значение 5? Я добавил код с оценкой внизу моего ответа.

7stud 03.04.2024 21:34

Расширение до цикла — не такое уж хорошее решение. Это могло бы привести к уменьшению кода, если бы были сотни переменных? Может быть. Ответ Райнера Йосвига очевиден: просто создайте программу с формами defparameter. eval плохой. Можно сделать лучше. Мы можем разделить символы и переменные: например. (a 1 b 2 c 3) можно превратить в (quote (a b c)) и (list 1 2 3). Мы позволяем этим выражениям вычисляться естественным образом, вставляя их в шаблон кода, а затем обрабатывая их параллельно for sym in '(a b c) and for val in (list 1 2 3).

Kaz 04.04.2024 02:46

Основная идея заключается в том, что у вас большой набор параметров, и вы, конечно же, хотите минимизировать код, исключить лишние определяемые параметры и т. д. Я думаю, что самое важное здесь — это читаемость кода. Тогда пары Имя-Значение с комментарием — лучший выбор, по крайней мере, для некоторых проблем)

Maxim 04.04.2024 04:59

@7stud: вопрос EVAL всегда заключается в следующем: в какой среде я оцениваю (интерпретирую или компилирую?) форму? Один пример: например, (let ((a 10)) (defpar-multiple b a)) не будет работать для локальной переменной a.

Rainer Joswig 04.04.2024 12:43
Ответ принят как подходящий

Просто создать несколько форм defparameter?

CL-USER 8 > (defmacro defpar (&rest var-and-value-list)
              `(progn ,@(loop for (var value) on var-and-value-list by #'cddr
                              collect `(defparameter ,var ,value))))
DEFPAR

CL-USER 9 > (pprint (macroexpand '(defpar a 1 b 2 c 3)))

(PROGN (DEFPARAMETER A 1)
       (DEFPARAMETER B 2)
       (DEFPARAMETER C 3))

Детали расширения DEFPARAMETER различаются в зависимости от реализации CL.

Имейте в виду, что макрорасширение DEFPARAMETER не стандартизировано в Common Lisp. Различные реализации расширяют это в разные формы. Многие из них также зависят от реализации. Кроме того, расширение может предоставлять функции среды разработки, такие как запись исходного кода или запись местоположения исходного кода. Поэтому лучше не изобретать defparameter для нескольких форм, а использовать его повторно. Это гарантирует, что особенности реализации по-прежнему поддерживаются.

Спасибо! Замечательно, можно даже вставлять комментарии для отдельных переменных при вызове макроса! Очень полезно, когда у вас есть страницы переменных)

Maxim 03.04.2024 19:43

@Maxim Вам нужны страницы переменных? мне сейчас интересно

coredump 04.04.2024 13:42

почему бы и нет?) это обычная ситуация в физических моделях.. поэтому я и задал вопрос..

Maxim 04.04.2024 17:55

насколько я понимаю, здесь также можно использовать документацию, реализованную в defparameter при необходимости.

Maxim 04.04.2024 18:03

Странно, что замена параметра defparameter на оператор defvar в макросе не меняет поведения: мы по-прежнему можем изменить переменную в любое время, используя setf. Конечно, мы можем проверить, используя переменную погодыboundp, которая уже определена, но я ожидаю, что это должен сделать defvar.

Maxim 08.04.2024 11:02

@Maxim DEFPARAMETER или DEFVAR не имеют ограничивающего влияния на обновления через SETF.

Rainer Joswig 08.04.2024 12:32

Другие вопросы по теме