【问题标题】:Multiple (define)s in a CL style macroCL 样式宏中的多个(定义)
【发布时间】:2010-08-31 07:07:08
【问题描述】:

我目前正在学习如何在 Scheme 中编写 CL 风格的宏(define-macro)。举个简单的例子,我写了一个struct 宏,它定义了make-thingthing?thing-field 访问器等函数。

现在我想在一个宏中组合多个defines,但实际上只使用了最后一个。目前我正在使用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)

【问题讨论】:

  • 请注意,Guile 具有适当的卫生宏,因此使用它们比使用 define-macro 更好。 (您可能可以在 guile 邮件列表中获得有关此方面的帮助。)
  • @Eli:没错,但我特意练习的目的是编写 CL 风格的宏。我仍然不确定是追求Scheme还是CL,所以我首先学习“便携”技能......
  • 这仅在非常肤浅和肤浅的方式上才有意义。卫生宏与符号 defmacros 有很大不同,它类似于 defmacro vs CPP 宏。
  • @Eli -- 这就是为什么我想先学习 CL 风格的 defmacros:它们在 CL and Scheme 中。我还没有选择专注于哪个 LISP。从长远来看,我会同时学习它们以及 Clojure。但是现在,defmacros 让我可以毫不费力地切换到 CL 并返回,所以我先学习它们。

标签: macros scheme lisp common-lisp


【解决方案1】:

这里不需要eval;使用begin 将这些定义组合到一个列表中;即,要扩展的模板应为以下形式:

`(begin 
   ,@(map ...)
   (define ...)
   (define ...)
   ...)

编辑:

按照 OP 的建议将 for-each 更改为 map

【讨论】:

  • 成功了,谢谢! :) 我宁愿尽可能避免 eval... 其他读者注意:使用 ,@(map...) 而不是 ,@(for-each...)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-14
  • 1970-01-01
  • 2012-10-04
  • 1970-01-01
  • 2016-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多