2016-11-14 67 views
1

下面的代码实现了一个带有隐式可选参数的宏调用,因为它隐藏在& rest参数中。有没有更好的方法来编写宏(及其支持函数) - 可能通过使用&可选关键字(或者其他方式)使可选参数显式化?最好是第一个参数是必需的,第二个是可选的,并且需要许多其余的参数。也希望保留宏定义简单,由支撑作用所做的工作,如果可能的话(但想学习更多先进的方法太):按顺序指定可选参数

(defstruct action 
    name duration slot1 slot2 slot3) 

(defmacro define-action (name &rest rest) 
    `(install-action ',name ',rest)) 

(defun install-action (name &rest rest) 
    (let* ((slots (first rest)) 
     (duration (if (numberp (first slots)) 
         (prog1 (first slots) 
           (setf slots (cdr slots)))        
        0)) 
     (action (make-action :name name :duration duration 
        :slot1 (first slots) :slot2 (second slots) 
        :slot3 (third slots)))) 
    (print action))) 

(define-action move a b c) ;first example no duration 

(define-action move 1 a b c) ;second example with duration=1 

#S(ACTION :NAME MOVE :DURATION 0 :SLOT1 A :SLOT2 B :SLOT3 C) 
#S(ACTION :NAME MOVE :DURATION 1 :SLOT1 A :SLOT2 B :SLOT3 C) 

澄清的附加点:上面的槽值是真的不同规范表示为(有时深度嵌套)lisp树。函数install-action解释规范并将其语义内容安装到数据库中。

+1

如果其他参数是必需的,最好使它们成为常规的命名参数。这样,宏的用户可以从lambda列表中看到他们应该给它的内容,而不必猜测(/阅读文档)。可选的持续时间可以是最后的关键字/可选参数。或者你可以为宏指定'(name(&optional(duration 0))slot1 slot2 slot3)'。 – jkiiski

+0

如果我能使用它,我宁愿使用您的解决方案。 (不知道必填项/可选项可能会混在一起)你如何得到 (defmacro define-action(name(&optional(duration 0))slot1 slot2 slot3) '(install-action',name',duration ',slot1',slot2',slot3)) to macroexpand properly? (ps:如何在Stackoverflow上记录注释的首选解决方案?) – davypough

+0

这应该起作用:'(macroexpand'(define-action foo(3)abc))'=>'(INSTALL-ACTION'FOO'3' A'B'C)'。请记住,您必须将持续时间放在身边(如果您没有持续时间,则必须将空闲的身体放置)。 – jkiiski

回答

3

参数和参数列表:风格

这是有明确的参数列表非常有用。 Common Lisp为它提供了广泛的支持。但即便如此,并不是每个参数列表的想法都可以被支持正如jkiiski在他的评论中指出的那样,有一个发言参数列表总是有帮助的:它帮助开发者,编译器可以在编译时捕获一些错误,并且Lisp可以提供更好的调试信息。

其中一种样式规则:可选参数应该位于参数列表的末尾。 Common Lisp本身至少违反了一个地方(现在只能记住一个函数),并且总是很痛苦且容易出错。

修复的arglist中INSTALL-ACTION

(defun install-action (name slots &optional (duration 0)) 
    ...) 

修复宏的arglist中,也

这样使用它:

(define-action move (a b c) 1) 

的事务清单可能更好地被分组在宏接口中。

(defmacro define-action (name slots &optional duration) 
    ...) 

甚至使用关键字命名的参数:

(define-action move :slots (a b c) :duration 1) 

它变得更长,但可读性大大提高。

旁边的问题:我们需要一个宏DEFINE-ACTION,为什么?

的主要原因为这样一个宏通常是:

  • 少引述
  • 特殊语法
  • 编译时的副作用
  • 扩展到其它宏调用
+1

缺少一个词:“可选参数应该在参数列表的”。 – coredump

+1

@coredump:非常感谢,修复。 –

+0

我希望把可选参数放在lambda列表中,以方便阅读。它只是一个数字,槽参数可能是复杂的树(参见上面的问题编辑)。担心编写规范时可能会太容易忽略可选参数。是槽:关键字是最好的方式,尽管它们都是必需的? – davypough