我的 lisp 宏在最新的诡计中停止工作
My lisp macro stops working in latest guile
我有一个我在 2010 年写的宏,它用于使用 Alists 管理像 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 in JavaScript 更新了这个宏(它基于方案),当我调用它时,它返回 false
并且想知道这是否是它在诡计中的工作方式。但事实证明,它根本不起作用。它显示此错误:
While compiling expression: ERROR: Syntax error: unknown location:
definition in expression context, where definitions are not allowed,
in form (define (make-point #{ g746}# #{ g747}#) (map cons (quote (x
y)) (list #{ g746}# #{ g747}#))
为什么我会遇到这个错误以及如何修复它,让它再次发挥作用?很久以前我不记得我是如何测试这段代码的,但是使用加载函数打开 guile 或将代码复制粘贴到解释器中都会给出同样的错误。
我在 GNU/Linux 上使用 guile 2.0.14。
PS:我更喜欢使用 lisp 宏 IMO,它们优于奇怪的方案卫生宏。
看起来现代 guile 方案没有将 if 中的 begin 视为启动新定义上下文的有效选项。这可能是 scheme spec donough 的错误或更好的对齐方式。但是下面的示例代码显示了为更新的 guile 修复代码的技术(您可能需要创建 define-values,因为它是对 guile 的更新的补充。P.S。在 guile 中使用 lisps 宏是一个难题并且计划多了会惹麻烦,宏就像parens,习惯了就自然了。
这是代码,
(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)
...))))))))
我有一个我在 2010 年写的宏,它用于使用 Alists 管理像 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 in JavaScript 更新了这个宏(它基于方案),当我调用它时,它返回 false
并且想知道这是否是它在诡计中的工作方式。但事实证明,它根本不起作用。它显示此错误:
While compiling expression: ERROR: Syntax error: unknown location: definition in expression context, where definitions are not allowed, in form (define (make-point #{ g746}# #{ g747}#) (map cons (quote (x y)) (list #{ g746}# #{ g747}#))
为什么我会遇到这个错误以及如何修复它,让它再次发挥作用?很久以前我不记得我是如何测试这段代码的,但是使用加载函数打开 guile 或将代码复制粘贴到解释器中都会给出同样的错误。
我在 GNU/Linux 上使用 guile 2.0.14。
PS:我更喜欢使用 lisp 宏 IMO,它们优于奇怪的方案卫生宏。
看起来现代 guile 方案没有将 if 中的 begin 视为启动新定义上下文的有效选项。这可能是 scheme spec donough 的错误或更好的对齐方式。但是下面的示例代码显示了为更新的 guile 修复代码的技术(您可能需要创建 define-values,因为它是对 guile 的更新的补充。P.S。在 guile 中使用 lisps 宏是一个难题并且计划多了会惹麻烦,宏就像parens,习惯了就自然了。
这是代码,
(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)
...))))))))