Мой макрос lisp перестает работать в последней версии
У меня есть макрос, который я написал в 2010 году, он был для управления структурами, как в Common Lips, с использованием Alists (здесь весь файл, включая функции 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)))))))
Работало нормально. Я недавно обновил этот макрос для моих губ в JavaScript (он основан на схеме), и когда я его вызывал, он возвращался false
и хотел знать, так ли это будет работать в коварстве. Но оказывается, что это не работает в коварстве вообще. Это показывает эту ошибку:
При компиляции выражения: ОШИБКА: синтаксическая ошибка: неизвестное расположение: определение в контексте выражения, где определения недопустимы, в форме (define (make-point #{ g746}# #{ g747}#) (map cons (quote (x y)) (список #{ g746}# #{ g747}#))
Почему у меня есть эта ошибка и как ее исправить, чтобы она снова работала в guile? Я был давно, я не помню, как я тестировал этот код, но открытие guile с помощью функции load или копирование, вставка кода в интерпретатор - все выдает ту же ошибку.
Я использую guile 2.0.14 на GNU / Linux.
PS: я предпочитаю использовать макросы lisp ИМО, они превосходят странные схемы гигиенических макросов.
1 ответ
Похоже, что современная схема guile не видит начала в if в качестве допустимой опции для запуска нового определения контекста. Возможно, это ошибка или лучшее выравнивание схемы дону. Но в следующем примере кода показан метод исправления вашего кода для более поздней версии guile (вам может понадобиться создать define-values, так как это более свежее дополнение к guile. PS использование макросов lisps в guile - это обман, и вы попадете в Беда, если вы планируете много спланировать, макросы похожи на парены, если вы привыкнете, они будут выглядеть естественно.
Вот код,
(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)
...))))))))