2015-11-15 6 views
6

Когда я компилирую следующий код, SBCL жалуется, что значение g! -unit и g! -unit не определены. Я не уверен, как отлаживать это. Насколько я могу судить, сглаживание не работает.Макросы, которые записывают макросы - ошибка компиляции

Когда сплюснута достигает неучтенной части высвобождения, кажется, что вся часть рассматривается как атом. Правильно ли это звучит?

Следующая использует код из книги Let over Lambda:

Paul Graham Утилиты

(defun symb (&rest args) 
    (values (intern (apply #'mkstr args)))) 

(defun mkstr (&rest args) 
    (with-output-to-string (s) 
    (dolist (a args) (princ a s)))) 

(defun group (source n) 
    (if (zerop n) (error "zero length")) 
    (labels ((rec (source acc) 
      (let ((rest (nthcdr n source))) 
       (if (consp rest) 
        (rec rest (cons (subseq source 0 n) acc)) 
        (nreverse (cons source acc)))))) 
    (if source (rec source nil) nil))) 

(defun flatten (x) 
    (labels ((rec (x acc) 
      (cond ((null x) acc) 
        ((atom x) (cons x acc)) 
        (t (rec (car x) (rec (cdr x) acc)))))) 
    (rec x nil))) 

Пусть Over Lambda Утилиты - Глава 3

(defmacro defmacro/g! (name args &rest body) 
    (let ((g!-symbols (remove-duplicates 
       (remove-if-not #'g!-symbol-p 
           (flatten body))))) 
    `(defmacro ,name ,args 
     (let ,(mapcar 
       (lambda (g!-symbol) 
       `(,g!-symbol (gensym ,(subseq 
             (symbol-name g!-symbol) 
             2)))) 
       g!-symbols) 
     ,@body)))) 

(defun g!-symbol-p (symbol-to-test) 
    (and (symbolp symbol-to-test) 
     (> (length (symbol-name symbol-to-test)) 2) 
     (string= (symbol-name symbol-to-test) 
       "G!" 
       :start1 0 
       :end1 2))) 

(defmacro defmacro! (name args &rest body) 
    (let* ((o!-symbols (remove-if-not #'o!-symbol-p args)) 
     (g!-symbols (mapcar #'o!-symbol-to-g!-symbol o!-symbols))) 
    `(defmacro/g! ,name ,args 
     `(let ,(mapcar #'list (list ,@g!-symbols) (list ,@o!-symbols)) 
      ,(progn ,@body))))) 

(defun o!-symbol-p (symbol-to-test) 
    (and (symbolp symbol-to-test) 
     (> (length (symbol-name symbol-to-test)) 2) 
     (string= (symbol-name symbol-to-test) 
       "O!" 
       :start1 0 
       :end1 2))) 

(defun o!-symbol-to-g!-symbol (o!-symbol) 
    (symb "G!" (subseq (symbol-name o!-symbol) 2))) 

Пусть Over Lambda - Глава 5

(defun defunits-chaining (u units prev) 
    (if (member u prev) 
     (error "~{ ~a~^ depends on~}" 
      (cons u prev))) 
    (let ((spec (find u units :key #'car))) 
    (if (null spec) 
     (error "Unknown unit ~a" u) 
     (let ((chain (second spec))) 
      (if (listp chain) 
       (* (car chain) 
       (defunits-chaining 
        (second chain) 
        units 
        (cons u prev))) 
       chain))))) 

(defmacro! defunits (quantity base-unit &rest units) 
    `(defmacro ,(symb 'unit-of- quantity) 
     (,g!-unit-value ,g!-unit) 
    `(* ,,g!-unit-value 
     ,(case ,g!-unit 
       ((,base-unit) 1) 
       ,@(mapcar (lambda (x) 
          `((,(car x)) 
           ,(defunits-chaining 
           (car x) 
           (cons 
           `(,base-unit 1) 
           (group units 2)) 
           nil))) 
          (group units 2)))))) 
+0

По какой-то причине функция g! -symbol-p не компилируется в Clozure Common Lisp Version 1.11 (DarwinX8664)! –

+0

Что-то похожее на то, что делал SBCL? – SpyroSoft

ответ

6

Это своего рода сложно:

Проблема: Вы предполагаете, что кавычка/запятая выражения простые списки.

Вы должны задать себе этот вопрос:

Что такое представление выражения кавычки/запятой?

Это список?

Фактически полное представление неуказано. См. Здесь: CLHS: Section 2.4.6.1 Notes about Backquote

Мы используем SBCL. Смотрите это:

* (setf *print-pretty* nil) 

NIL 


* '`(a ,b) 

(SB-INT:QUASIQUOTE (A #S(SB-IMPL::COMMA :EXPR B :KIND 0))) 

Таким образом, выражение запятой представлен структурой типа SB-IMPL::COMMA. Разработчики SBCL считали, что это представление помогает, когда такие списки backquote должны быть напечатаны красивым принтером.

Поскольку ваши flatten трактует структуры, как атомы, это не будет выглядеть внутри ...

Но это специфическое представление SBCL. Clozure CL делает что-то еще, и LispWorks снова делает что-то еще.

Clozure CL:

? '`(a ,b) 
(LIST* 'A (LIST B)) 

LispWorks:

CL-USER 87 > '`(a ,b) 
(SYSTEM::BQ-LIST (QUOTE A) B) 

Отладочные

Так как вы узнали, что каким-то образом flatten был вовлечен, шаги следующей отладки являются:

Во-первых: отследите функцию flatten и посмотрите, с какими данными она вызывается и что она возвращает.

Поскольку мы не уверены, какие данные на самом деле, можно INSPECT.

отладки Пример использования SBCL:

* (defun flatten (x)                       
    (inspect x)                        
    (labels ((rec (x acc)                      
       (cond ((null x) acc)                   
        ((atom x) (cons x acc))                 
        (t (rec (car x) (rec (cdr x) acc))))))             
     (rec x nil))) 
STYLE-WARNING: redefining COMMON-LISP-USER::FLATTEN in DEFUN 

FLATTEN 

Над называет INSPECT на данных аргументов. В Common Lisp Инспектор обычно является чем-то, где можно интерактивно проверить структуры данных.

В качестве примера мы называем flatten с кавычка выражением:

* (flatten '`(a ,b)) 

The object is a proper list of length 2. 
0. 0: SB-INT:QUASIQUOTE 
1. 1: (A ,B) 

Мы в интерактивном Inspector. Команды теперь доступны:

> help 

help for INSPECT: 
    Q, E  - Quit the inspector. 
    <integer> - Inspect the numbered slot. 
    R   - Redisplay current inspected object. 
    U   - Move upward/backward to previous inspected object. 
    ?, H, Help - Show this help. 
    <other>  - Evaluate the input as an expression. 
Within the inspector, the special variable SB-EXT:*INSPECTED* is bound 
to the current inspected object, so that it can be referred to in 
evaluated expressions. 

Так команда 1 входит в структуру данных, то здесь список.

> 1 

The object is a proper list of length 2. 
0. 0: A 
1. 1: ,B 

Прогулка дальше:

> 1 

The object is a STRUCTURE-OBJECT of type SB-IMPL::COMMA. 
0. EXPR: B 
1. KIND: 0 

Здесь инспектор говорит нам о том, что объект является структурой определенного типа. Это то, что мы хотели знать.

теперь оставить инспектор с помощью команды q и функция flatten продолжается, и возвращает значение:

> q 

(SB-INT:QUASIQUOTE A ,B) 
+0

Спасибо. Вау, это структура. Я не думаю, что кто-то сделал портативную квазикотажную библиотеку, не так ли? – SpyroSoft

+1

Именно это объяснение я искал, чтобы понять, почему defmacro/g! макрос, определенный в главе 3 LOL (http://letoverlambda.com/index.cl/guest/chap3.html), не работает! благодаря –

0

Для кого-то, кто пытается получить defmacro! работать на SBCL, временное решение этой проблемы нащупать внутри структуры в процессе конец цитаты в Свести процедуры рекурсивно расплющить его содержимое:

(defun flatten (x) 
    (labels ((flatten-recursively (x flattening-list) 
      (cond ((null x) flattening-list) 
        ((eq (type-of x) 'SB-IMPL::COMMA) (flatten-recursively (sb-impl::comma-expr x) flattening-list)) 
        ((atom x) (cons x flattening-list)) 
        (t (flatten-recursively (car x) (flatten-recursively (cdr x) flattening-list)))))) 
    (flatten-recursively x nil))) 

Но это ужасно зависят от платформы. Если я найду лучший способ, я отправлю его.

 Смежные вопросы

  • Нет связанных вопросов^_^