Мой макрос lisp перестает работать в последней хитрости

У меня есть макрос, который я написал в 2010 году, он был для управления структурами, как в Common Lips, с использованием списков (вот весь файл, включая функции https://jcubic.pl/struct.txt).

(define-macro (defstruct name . fields)
  "Macro implementing structures in guile based on assoc list."
  (let ((names (map (lambda (symbol) (gensym)) fields))
        (struct (gensym))
        (field-arg (gensym)))
    `(if (not (every-unique ',fields))
        (error 'defstruct "Fields must be unique")
        (begin
          (define (,(make-name name) ,@names)
        (map cons ',fields (list ,@names)))
          ,@(map (lambda (field)
               `(define (,(make-getter name field) ,struct)
              (cdr (assq ',field ,struct)))) fields)
          ,@(map (lambda (field)
               `(define (,(make-setter name field) ,struct ,field-arg)
              (assq-set! ,struct ',field ,field-arg)
              ,field-arg)) fields)
          (define (,(make-predicate name) ,struct)
        (and (struct? ,struct)
             (let ((result #t))
               (for-each (lambda (x y)
                   (if (not (eq? x y)) (set! result #f)))
                 ',fields
                 (map car ,struct))
               result)))))))

Он работал нормально. Недавно я обновил этот макрос для своего LIPS в JavaScript (он основан на схеме), и когда я его вызываю , он возвращал false и хотел знать, как это будет работать хитростью. Но оказывается, что это совсем не хитрость. Он показывает эту ошибку:

При компиляции выражения: ОШИБКА: синтаксическая ошибка: неизвестное местоположение: определение в контексте выражения, где определения не разрешены, в форме (define (make-point # {g746} # # {g747} #) (map cons (quote (xy) ) (список # {g746} # # {g747} #))

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

Я использую хитрость 2.0.14 в GNU / Linux.

PS: Я предпочитаю использовать макросы lisp. IMO они превосходят гигиенические макросы со странной схемой.


person jcubic    schedule 15.04.2019    source источник


Ответы (1)


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

Вот код,

(define-macro (defstruct name . fields)
   "Macro implementing structures in guile based on assoc list."
   (let* ((names (map (lambda (symbol) (gensym)) fields))
          (struct    (gensym))
          (field-arg (gensym))
          (sname     (make-name name))
          (predname  (make-predicate name))
          (getnames  (map (lambda (f) (make-getter name f)) fields))
          (setnames  (map (lambda (f) (make-setter name f)) fields)))

      `(define-values (,sname ,predname ,@getnames ,@setnames)
         (if (not (every-unique ',fields))
             (error 'defstruct "Fields must be unique")
             (let ()
               (define (,sname ,@names)
                 (map cons ',fields (list ,@names)))
               ,@(map (lambda (field)
                  `(define (,(make-getter name field) ,struct)
                      (cdr (assq ',field ,struct)))) fields)
               ,@(map (lambda (field)
                  `(define (,(make-setter name field) ,struct ,field-arg)
                      (assq-set! ,struct ',field ,field-arg)
                  ,field-arg)) fields)
               (define (,predname ,struct)
                  (and (struct? ,struct)
                       (let ((result #t))
                          (for-each (lambda (x y)
                             (if (not (eq? x y)) (set! result #f)))
                           ',fields
                          (map car ,struct))
                          result)))

                 (values ,sname ,predname ,@getnames ,@setnames))))))

Вот версия define-values (посмотрите на код после #', чтобы узнать, что он делает)

(define-syntax define-values
   (lambda (x)
      (syntax-case x ()
        ((_ (f ...) code ...)
         (with-syntax (((ff ...) (generate-temporaries #'(f ...))))
           #'(begin
               (define f #f)
                ...
               (call-with-values (lambda () code ...)
                  (lambda (ff ...)
                     (set! f ff)
                     ...))))))))
person Stefan    schedule 15.04.2019
comment
Я думаю, что if можно было бы выполнить во время компиляции (в макросе, а не в результате), поскольку дан fields. Таким образом, результат может быть (begin ....) без if - person Sylwester; 15.04.2019