2016-11-14 71 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