LINUX.ORG.RU

Lisp: macro, variable


0

0

Вот хочу замутить такой макр:

(defmacro my_macro (list-table)
  (setf *sw-tb-cr* (eval (first (eval list-table)))
	*sw-tb-nx* (rest (eval list-table)))
	(setf (gethash (caddr *sw-tb-cr*) (eval (car *sw-tb-cr*)))
	      (cadddr *sw-tb-cr*))
	(cond ((null *sw-tb-nx*)  nil)
	      (t (create-state-table *sw-tb-nx*))))

Здесь, 
(defvar *sw-tb-nx* (list 1)) ; начальная
(defvar *sw-tb-cr* (list 1)) ; инициализация
(defvar *ABC* (list '*A* '*B*)) ; A и B - тоже списки
Никак не получается разобраться с переменными. Подскажите, как 
правильно реализовать этот макр ??? Можно ли обойтись без глобальных
переменных ? (пока не получается). Ну и как вообще делается такое ?
В том примере, что я привел, при компиляции выдается ошибка:

;Compile-time error:
;     (in macroexpansion of (CREATE-STATE-TABLE *SW-TB-NX*))
;   (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
;   The value 1 is not of type LIST.
Не понятно при чём тут единица ? Я же *sw-tb-nx* переписываю, единица
только для инициализации.

anonymous

Ты бы написал, что пытаешься сделать, и во что этот макро должен развернуться.

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

Он должен заполнить хэш-таблицу во время компиляции, беря данные из списка списков *ABC*, и вернуть NIL.

anonymous
()

Чёто страшное делает твой макр. Опиши подробнее, чего ты от него хочеш.
 Глобальные переменные без особой надобности юзать ИМХО не следует,
 возможно лучше было бы использовать closure (замыкание) вместо.
 А в твоём случае вообще вполне хватает локальных, ты ведь не
 используеш предыдущие значения переменных *sw-tb-...*

Тупо переписываю твой макр в более приемлемом на мой взгляд стиле:

(defmacro my-macro (list-table)
  (let* (
    (ev (eval list-table))
    (cr (eval (first ev)))
    (nx (rest ev)))
        (setf (gethash (caddr cr) (eval (car cr))) (cadddr cr))
        (if nx (create-state-table nx) nil)))

Есть подозрение, что логику работы неплохо бы пересмотреть, чтобы
 избавиться от многочисленных возможно лишних eval и car caddr cadddr.

> Не понятно при чём тут единица ?
> Я же *sw-tb-nx* переписываю, единица только для инициализации.

Очевидно причина в содержимом аргумента или внутри create-state-table.
 У меня такой вариант ашыпки не производит:

(defun create-state-table (x) (format nil "~S~%" x))

(my_macro '((list (make-hash-table)) 2 3 4 5 6 7 8 9 10))

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

Тупо копирнул себе твой макро, сделал C-x C-e (compile) и:

; caught ERROR:
;   (in macroexpansion of (CREATE-STATE-TABLE NX))
;   (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
;   The variable NX is unbound.

Что не так ?

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

Б-р-р-р... Тормознул. В макро должна быть рекурсия:

(defmacro my-macro (list-table)
  (let* (
    (ev (eval list-table))
    (cr (eval (first ev)))
    (nx (rest ev)))
        (setf (gethash (caddr cr) (eval (car cr))) (cadddr cr))
        (if nx (my-macro nx) nil))) ;; Это вместо ошибочного 
                                    ;; create-state-table

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

а какова структура аргумента? Вобщем, ИМХО было бы проще так:

(let ((ht (make-hash-table)))
  (defmacro fill-the-hash (key val &optional (get-result nil))
    (setf (gethash key) val)                   
    (if get-result (create-state-table ht) nil)))

; сохраняет в хеше значение
; генерит код nil
(fill-the-hash "somekey" "someval") 

; генерит код, который был вёрнут create-state-table
(fill-the-hash "somekey" "someval" t)

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

Но ошибка такая же:

; caught ERROR:
;   (in macroexpansion of (MY-MACRO NX))
;   (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
;   The variable NX is unbound.

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

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

> В макро должна быть рекурсия:

Ну должна так должна. По сути она мало чего меняет.

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

> Но ошибка такая же:

Не должно там быть ащыпки, гдето ты нетак переписал. А вообще,
 вот тебе простенький пример closure, сделай луче нечто подобное:

(let ((x 0))
  (defmacro add-x (n)
    (prog1 nil (incf x n)))

  (defmacro get-x () x))

(add-x 4) ; добавляет значение к х

(get-x) ; генерит числовую константу, равную накопленному

bugmaker ★★★★☆
()

(defmacro my-macro (keys values table)
  (let ((table-value (eval table)))
    (loop for key in (eval keys) for value in (eval values)
       do (setf (gethash key table-value) value))))

или я все равно не понял, что надо?

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

Аргумент, list-table - список списков.
Задаю списки
(defvar A1 (make-hash-table))
(defvar B1 (make-hash-table))
(defvar *A* (list 'A1 'A2 ... 'An)) ; Каждый 1-ый элемент списка -
(defvar *B* (list 'B1 'B2 ... 'Bn)) ; эш-таблица
....... и т.д.
(defvar *ABC* (list '*A* '*B*...'*N*))
Вот *ABC* и предаю в макро.
(my-macro *ABC*)
Идея такова, что работа макро не зависит от этих списков (главное
формат списков соблюдать), я просто изменяю значения списков, кидаю
на вход макро и он генерит, что мне надо.

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

> Не должно там быть ащыпки

Просто копирнул

(defmacro my-macro (list-table)
  (let* (
    (ev (eval list-table))
    (cr (eval (first ev)))
    (nx (rest ev)))
        (setf (gethash (caddr cr) (eval (car cr))) (cadddr cr))
        (if nx (my-macro nx) nil)))

; caught ERROR:
;   (in macroexpansion of (MY-MACRO NX))
;   (hint: For more precise location, try *BREAK-ON-SIGNALS*.)
;   The variable NX is unbound.
; compilation unit finished
;   caught 1 ERROR condition

У меня практически такой же код, и таже ошибка... Может чего не
правильно делаю ????

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

> Не должно там быть ащыпки

Просто копирнул

(defmacro my-macro (list-table) (let* ( (ev (eval list-table)) (cr (eval (first ev))) (nx (rest ev))) (setf (gethash (caddr cr) (eval (car cr))) (cadddr cr)) (if nx (my-macro nx) nil)))

; caught ERROR: ; (in macroexpansion of (MY-MACRO NX)) ; (hint: For more precise location, try *BREAK-ON-SIGNALS*.) ; The variable NX is unbound. ; compilation unit finished ; caught 1 ERROR condition

У меня практически такой же код, и таже ошибка... Может чего не правильно делаю ????

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

 Сравни результат выполнения таких прог:
-1---------------------------------------------------

(defvar *zzz* 1)

(defmacro qqq (x) (setf x (+ 1 (eval x))))

(defun a () (qqq *zzz*))
(defun b () (qqq *zzz*))
(defun c () (qqq *zzz*))

(format t "~S~%" *zzz*)

-2----------------------------------------------------
(defvar *zzz* 1)

(let ((n 0))
  (defmacro qqq (x) (incf n (eval x)))
  (defmacro ppp () n))

(defun a () (qqq *zzz*))
(defun b () (qqq *zzz*))
(defun c () (qqq *zzz*))

(format t "~S~%" (ppp))

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

Аааааа... не туда гянул

1----------

2
2
2

2---------

1
2
3

Ну эт понятно. Вот макро чего не пашет, что ты мне написал ?

(defmacro my-macro (list-table)
  (let* (
    (ev (eval list-table))
    (cr (eval (first ev)))
    (nx (rest ev)))
        (setf (gethash (caddr cr) (eval (car cr))) (cadddr cr))
        (if nx (my-macro nx) nil)))

А у тебя он комплица ?

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

> Ну эт понятно.

(1) это разве не подобно тому, что ты пытаешся сделать? Кака получится.

> Вот макро чего не пашет, что ты мне написал ?

А должен разве? 

(defmacro my-macro (list-table)
  (format t "expanding my-macro with '~S' as argument~%" list-table)
  (let* (
    (ev (eval list-table))
    (cr (eval (first ev)))
    (nx (rest ev)))
        (setf (gethash (caddr cr) (eval (car cr))) (cadddr cr))
        (if nx (my-macro nx) nil)))

При рекурсивном вызове в макро передаётся символ nx, а не его значение
 как ты можеш видеть из отладочного вывода. В следующей инкарнации
 с этим символом разумеется не связано ни одного значения, посему и...

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

> с этим символом разумеется не связано ни одного значения, посему и...

Я так и думал :( Так а как значение передать ?

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

так nx не глобальная ведь. и она передаёт в рекурсию остаток от 
списка (nx (rest (ev (eval list-table)))), где list-table -
формальный параметр, в качестве которого я сначала передаю глобальную
переменную *lala*, которая является списком списков. 
(my-macro *lala*) ну или так можно (?) 
(setf list-table *lala*) 
(my-macro list-table)
А потом уже при рекурсии я хочу передать не глобальную переменную,
а её остаток - nx - для последующего вычисления. Ну типа как в cond.

Ещё вопрос
(defmacro my-macro (list-table)
.............)
Если я хочу, чтоб он полностью вычислился пр компиляции, то 
list-table должна быть уже определена ? (до компиляции).
(setf list-table *lala*) Так ?

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

> (defvar *A* (list 'A1 'A2 ... 'An)) ; Каждый 1-ый элемент списка - > (defvar *B* (list 'B1 'B2 ... 'Bn)) ; эш-таблица

А зачем имена таблиц заквотил?

> (defvar *ABC* (list '*A* '*B*...'*N*))

И здесь тоже зачем?

> Если я хочу, чтоб он полностью вычислился пр компиляции, то > list-table должна быть уже определена ? (до компиляции). > (setf list-table *lala*) Так ?

Да, должна быть определена. Лучше всего использовать (eval-when ...

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

И таки дай тестовый набор данных и желаемый результат. А то с утра кроме того, что это должно вычислиться во время компиляции макро, ничего не понял :)

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

Блин. Исходник дома, но ща постараюсь идею сформулировать:

(defvar A1 (make-hash-table))
(defvar B1 (make-hash-table))
............ и т.д.
(defvar N1 (make-hash-table))

(defvar *A* (list 'A1 'A2 ... 'An)) ; Каждый 1-ый элемент списка -
(defvar *B* (list 'B1 'B2 ... 'Bn)) ; эш-таблица
....... и т.д.
(defvar *N* (list 'N1 'N2 ... 'Nn))
(defvar *ABC* (list '*A* '*B*...'*N*))
Имеем, N списков типа *A*, *B*....., где первый эл-т - Хэш-таблица
(пока пустая) остальные - ключи, данные.... И результирующий список
*ABC*, который объединяет все списки.

(setf list-table *ABC*)         ;инициализирую
(defmacro my-macro (list-table) ; Передаю *ABC* в макро 
  (let* (
    (ev (eval list-table))  ; в ev получаю *ABC*
    (cr (eval (first ev)))  ; извлекаю 1-ый список *A*
    (nx (rest ev)))         ; запоминаю остаток (*B* *C* ...)
        (setf (gethash (caddr cr) (eval (car cr))) (cadddr cr))
        ; здесь в Хэш-табл A1 по ключу A3 записываю значение A4
        (if nx (my-macro nx) nil))) ; Передаю остаток списка в 
        рекурсию, для такого же вычисления. Т.е. в Хэш-табл B1 
        по ключу B3 записываю значение B4 и т.д., пока не закончатся
        списки в списке *ABC*.
Пока проблема такая, что не могу передать значение в рекурсивный
вызов. При компиляции - The variable NX is unbound. И это правильно.
И вопрос - как передать значение nx в рекурсию ????

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

А, забыл, что должно получится после правильного исполнения:

(gethash A3 A1)
> A4

(gethash B3 B1)
> B4
......

(gethash N3 N1)
> N4

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

> Блин. Исходник дома, но ща постараюсь идею сформулировать:
<skip>

Теперь более менее понятнен алгоритм (но совершенно не ясно его предназначение ;) Ну да ладно.

Таки повторю вопрос: квотирование имён в списках

(defvar *A* (list 'A1 'A2 ... 'An))
(defvar *B* (list 'B1 'B2 ... 'Bn))
.......
(defvar *N* (list 'N1 'N2 ... 'Nn))
(defvar *ABC* (list '*A* '*B*...'*N*))

принципиально? Т.е. эти списки ещё где-то используются? Или это
обусловленно чем-то другим?

Просто постановка задачи смахивает на полную кривизну (если это,
конечно, не условия задачи :)

Далее: тебе надо получить результат
а) во время компиляции программы
б) именно во время компиляции данного макроса

Если первое, то этого можно добиться другим путём и без заморочки с
макрами.

Если второе, то это тоже требует обоснования :), ибо самый простой
путь - на этапе загрузки/компиляции объявить функцию, которая должна
всё это сделать, а в макре просто её вызвать:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defun my-fun (...)
      ...
      ... (my-fun ...)..))

(defmacro my-macro (x)
  (my-fun x))

Но это почти не отличается от первого варианта, ибо, в данном случае,
можно просто сделать не

  (my-macro ...)

а

  #.(my-fun ...)

Да, и все твои объявления переменных должны тоже быть в eval-when ...

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

> Теперь более менее понятнен алгоритм

Повторю вопрос:

(setf list-table *ABC*)         ;инициализирую
(defmacro my-macro (list-table) ; Передаю *ABC* в макро 
  (let* (
    (ev (eval list-table))  ; в ev получаю *ABC*
    (cr (eval (first ev)))  ; извлекаю 1-ый список *A*
    (nx (rest ev)))         ; запоминаю остаток (*B* *C* ...)
        (setf (gethash (caddr cr) (eval (car cr))) (cadddr cr))
        ; здесь в Хэш-табл A1 по ключу A3 записываю значение A4
        (if nx (my-macro nx) nil))) ; Передаю остаток списка в 
        рекурсию, для такого же вычисления. Т.е. в Хэш-табл B1 
        по ключу B3 записываю значение B4 и т.д., пока не закончатся
        списки в списке *ABC*.
Пока проблема такая, что не могу передать значение в рекурсивный
вызов. При компиляции - The variable NX is unbound. И это правильно.
И вопрос - как передать значение nx в рекурсию ????
Я ж не спрашивал как сделать лучше, по-другому, без макро и т.д. :)
Столкнулся с такой проблемой, хочу её решить, если у кого по существу, что есть... буду рад...

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

> И вопрос - как передать значение nx в рекурсию ????

Никак. Рекурсивно раскрывающиеся макры ещё бывают. Но чтобы из "расчётной" части макры рекурсивно вызвать её саму с передачей параметров по имени - такого я ещё не видел :)

> Я ж не спрашивал как сделать лучше, по-другому, без макро и т.д. :)

Ок, но...

> Столкнулся с такой проблемой, хочу её решить

Ты же сам выяснил, что именно _так_ её не решить:

> При компиляции - The variable NX is unbound. И это правильно.

Как решить - я показал: фактически уйти от оформления рекурсивных вычислений в самой "расчётной" части макр.

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

Как ещё вариант, могу предложить

; тут обработка
(defun bla (x)
  (format t "~S~%" x)
  (if x
    (bla (rest x))
    nil)) 

; нерекурсивный макрос
(defmacro my-macro (arg)
  (bla (symbol-value arg)))

(defparameter *ABC* '(1 2 3 4 5))

(my-macro *ABC*)

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

> Никак.

А, ну так понятно тог

> Столкнулся с такой проблемой, хочу её решить >> Ты же сам выяснил, что именно _так_ её не решить

Ну то, что компилятор на меня ругается - эт ещё ничего не значит :) Я блин такой лиспер, что аж... :) По-этому и спросил, как это сделать. Выяснилось, что никак...)

> Как решить - я показал

Спасибо. Буду пробовать.

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

bla реализует рекурсивную обработку. symbol-value получает значение переменной с именем, хранящимся в arg (макры получают имена переменных, а не их значения).

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