2012-02-13 37 views
0

試圖實現其擴展的三重參數的無限列表到λ-功能檢查的參數(對象)的宏。如何展開反引號外的名單 - 我在宏定義

例如

(where >= amount 5 equalp name "george") 

=> 

#'(lambda (arg) 
      (and 
      (>= (amount arg) 5) 
      (equalp (name arg) "george"))) 

我相當接近這個宏定義:

(defmacro where (&rest list-of-argument-triplets) 
    `#'(lambda (arg) 
     (and 
      ,(do ((counter 0 (+ counter 3)) (liste (list))) 
       ((>= counter (list-length list.of-argument-triplets)) liste) 
       (push `(,(nth counter list-of-argument-triplets) 
          (,(nth (+ counter 1) list-of-argument-triplets) arg) 
          ,(nth (+ counter 2) list-of-argument-triplets) 
          liste))))) 

但這擴展到

#'(lambda (arg) 
    (and ((>= (amount arg) 5) 
      (equalp (name arg) "george")))) 

這是後 「和」 太多了一個括號。作爲一個結論,我將不得不在結果表單前使用@,但是然後將「@list」視爲 ,就好像它是一個參數名稱,因此我得到一個無值錯誤,而不是擴大名單。

 *** - RETURN-FROM: variable @LISTE has no value 

我該如何解決這個問題?

回答

1

代碼味道:您使用NTH訪問列表的元素。

我會先定義一個輔助功能,這使得從平面列表三種元素列表的列表:

(defun triplets (list) 
    (loop while list 
     collect (list (pop list) 
         (pop list) 
         (pop list)))) 

CL-USER 1 > (triplets '(a b c d e f g h i)) 
((A B C) (D E F) (G H I)) 

宏然後稍微簡單的寫:

(defmacro where (&rest flat-triplets) 
    `#'(lambda (arg) 
     (and 
     ,@(mapcar (lambda (triplet) 
        (destructuring-bind (fn accessor item) 
         triplet 
         `(,fn (,accessor arg) ,item))) 
        (triplets flat-triplets)))) 


CL-USER 2 > (macroexpand-1 '(where >= amount 5 equalp name "george")) 
(FUNCTION (LAMBDA (ARG) (AND (>= (AMOUNT ARG) 5) (EQUALP (NAME ARG) "george")))) 
T 
+1

謝謝,它確實有效。但只是作爲一個教訓: 1 - 爲什麼nth作爲訪問者不好的風格? 2 - 將可能適用於可能的方法? – Sim 2012-02-13 19:57:23

+0

@Sim:如果你想通過索引訪問元素,然後使用一個數組。 Lisp中的列表是鏈接列表。所以你需要遍歷列表來訪問第n個元素 - 每一次。最便宜的操作是FIRST和REST。然後使用像MAPCAR這樣的列表操作 - 而不是像DO那樣的迭代。 – 2012-02-13 20:34:25