常见的Lisp:宏如何使用程序生成的名称定义其他方法/宏? [英] common lisp: how can a macro define other methods/macros with programmatically generated names?

查看:97
本文介绍了常见的Lisp:宏如何使用程序生成的名称定义其他方法/宏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我意识到我的代码的某些部分由看起来相似的方法组组成(就像我有多个三重奏:一个辅助函数,该辅助函数被其他两个供程序员使用的函数调用).我正在尝试编写一个宏,该宏将为我定义这三个函数,因此我需要做的就是调用该宏.但是,我的尝试导致了带有引号而不是生成的名称作为新符号的带引号的defun和函数调用.我在做什么错了?

示例(错误代码)

(defmacro def-trio (base-name)
  (let 
    ((helper-name (format nil "helper-~a" base-name))
     (method-1 (format nil "~a-1" base-name))
     (method-2 (format nil "~a-2" base-name)))
    `(progn 
          (defun ,helper-name () 'helper-called)
          (defun ,method-1 () (,helper-name) '1-called)
          (defun ,method-2 () (,helper-name) '2-called))))

现在发生以下情况:

(def-trio my-trio)

==>

(PROGN (DEFUN "helper-MY-TRIO" () 'HELPER-CALLED)
       (DEFUN "MY-TRIO-1" () ("helper-MY-TRIO") '1-CALLED)
       (DEFUN "MY-TRIO-2" () ("helper-MY-TRIO") '2-CALLED))

此外,在我学会了如何使它工作之后,如果我让此宏定义其他宏而不是其他函数,是否还有其他问题?我阅读了如何编写宏定义常见Lisp中的宏,但我认为我的问题有所不同,因为我在询问以编程方式生成的符号/名称.我愿意接受纠正:)谢谢!

解决方案

尝试一下:

对您的原始定义进行了以下更改-第一个更改是至关重要的:

  1. 使用(intern ... package)将每个计算出的符号名称与基本名称插入同一包中.
  2. 引入了变量package,该变量已绑定到提供的base-name符号的包中.
  3. let更改为let*,以允许在后续变量中引用新引入的变量package.
  4. 将helper方法的前缀更改为大写以匹配常规Lisp符号的约定.

I realized that a certain section of my code consists of groups of methods that look similar (like I have multiple trios: a helper function that gets called by two other functions meant for the programmer). I'm trying to write a macro that will define these three functions for me so that all I need to do is call the macro. But my attempt results in defuns and function calls that have quoted strings instead of the generated names as new symbols. What am I doing wrong?

Example (incorrect code)

(defmacro def-trio (base-name)
  (let 
    ((helper-name (format nil "helper-~a" base-name))
     (method-1 (format nil "~a-1" base-name))
     (method-2 (format nil "~a-2" base-name)))
    `(progn 
          (defun ,helper-name () 'helper-called)
          (defun ,method-1 () (,helper-name) '1-called)
          (defun ,method-2 () (,helper-name) '2-called))))

Now the following happens:

(def-trio my-trio)

==>

(PROGN (DEFUN "helper-MY-TRIO" () 'HELPER-CALLED)
       (DEFUN "MY-TRIO-1" () ("helper-MY-TRIO") '1-CALLED)
       (DEFUN "MY-TRIO-2" () ("helper-MY-TRIO") '2-CALLED))

Also, after I learn how to get this working, are there any extra gotcha's if I had this macro define other macros instead of other functions? I read How do I write a macro-defining macro in common lisp but I think my question is a little different because I'm asking about programmatically generated symbols/names. I'm open to being corrected though :) Thanks!

解决方案

Try this:

(defmacro def-trio (base-name)                                         ; changes:
  (let*                                                                ; 3.
    ((package (symbol-package base-name))                              ; 2.
     (helper-name (intern (format nil "HELPER-~a" base-name) package)) ; 1. 4.
     (method-1 (intern (format nil "~a-1" base-name) package))         ; 1.
     (method-2 (intern (format nil "~a-2" base-name) package)) )       ; 1.
    `(progn 
          (defun ,helper-name () 'helper-called)
          (defun ,method-1 () (,helper-name) '1-called)
          (defun ,method-2 () (,helper-name) '2-called) )))

The following changes were made to your original definition -- the first change is the crucial one:

  1. Interned each of computed symbol names into the same package as the base name using (intern ... package).
  2. Introduced the variable package which is bound to the package of the supplied base-name symbol.
  3. Changed let to let* to allow the newly introduced variable package to be referenced in subsequent variables.
  4. Changed the prefix of the helper method to upper case to match the convention for normal Lisp symbols.

这篇关于常见的Lisp:宏如何使用程序生成的名称定义其他方法/宏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆