我目前正在学习如何在 Scheme 中编写 CL 样式宏 (define-macro)。作为一个简单的例子,我写了一个 struct
定义类似 make-thing
的函数的宏, thing?
, thing-field
访问器等。
现在我想合并多个 define
s 在单个宏中,但实际上只使用了最后一个。目前我正在使用 eval
全局定义功能(?),但必须有一些更好的方法......有什么想法吗?
到目前为止的代码:
;(use-modules (ice-9 pretty-print))
(define-macro (struct name key table fields)
(for-each
(lambda (field)
(eval
`(define ,(string->symbol (string-append (symbol->string name) "-" (symbol->string field)))
(lambda (x)
(if (,(string->symbol (string-append (symbol->string name) "?")) x)
(cadr (assq (quote ,field) (cdr x)))
#f)))
(interaction-environment)))
fields)
(eval
`(define ,(string->symbol (string-append (symbol->string name) "?"))
(lambda (x)
(and
(list? x)
(eq? (car x) (quote ,name))
,@(map (lambda (field) `(assq (quote ,field) (cdr x))) fields)
#t)))
(interaction-environment))
(eval
`(define ,(string->symbol (string-append "make-" (symbol->string name)))
(lambda ,fields
(list (quote ,name)
,@(map (lambda (field) `(list (quote ,field) ,field)) fields))))
(interaction-environment))
(eval
`(define ,(string->symbol (string-append "save-" (symbol->string name)))
(lambda (x)
(if (,(string->symbol (string-append (symbol->string name) "?")) x)
(call-with-output-file ; TODO: In PLT mit zusaetzlichem Parameter #:exists 'replace
(string-append "data/" ,(symbol->string table) "/"
(,(string->symbol (string-append (symbol->string name) "-" (symbol->string key))) x))
(lambda (out) (write x out)))
#f)))
(interaction-environment))
`(define ,(string->symbol (string-append "get-" (symbol->string name)))
(lambda (id)
(let ((ret (call-with-input-file (string-append "data/" ,(symbol->string table) "/" id) read)))
(if (,(string->symbol (string-append (symbol->string name) "?")) ret)
ret
#f))))
; TODO: (define (list-customers . search-words) ...)
)
(struct customer id customers (id name name_invoice address_invoice zip_invoice city_invoice state_invoice))
;(pretty-print (macroexpand '(struct customer id customers (id name name_invoice address_invoice zip_invoice city_invoice state_invoice))))
;(newline)
(define c (make-customer "C-1001" "Doe, John" "John Doe" "Some-Street" "Some-Zip" "Some-City" "Germany"))
(write c)
(newline)
(write (customer-id c))
(newline)
(write (customer-name c))
(newline)
(save-customer c)
(write (get-customer "C-1001"))
(newline)
最佳答案
这里不需要eval
;使用 begin
将这些定义组合成一个列表;即,要扩展的模板应采用以下形式:
`(begin
,@(map ...)
(define ...)
(define ...)
...)
编辑:
按照 OP 的建议将 for-each
更改为 map
。
关于macros - CL 样式宏中的多个(定义),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3606736/