2011-07-26 55 views
1

我想在通用lisp中執行一個宏,該宏應該在其參數之一中包含由插槽和字符串組成的列表。原型如下:處理插槽和字符串列表中的值

(defclass time-info() 
    ((name :initarg name) 
    (calls :initarg calls) 
    (second :initarg second) 
    (consing :initarg consing) 
    (gc-run-time :initarg gc-run-time))) 

(defun print-table (output arg-list time-info-list)()) 

想法是打印一個基於定義其結構的arg-list的表。這是一個函數調用的示例:

(print-table *trace-output* 
      '("|" name "||" calls "|" second "\") 
      my-time-info-list) 

這將在trace輸出的ascII中打印一張表格。問題是,我不知道如何明確地獲取列表中的元素,以便在我的宏的不同部分中使用它們。

我不知道如何做到這一點,但我相信它可以做到。也許你可以幫我:)

+0

爲什麼要在一個宏,而不是一個功能?數組的ASCII表示?哪個陣列? –

+0

':initarg'通常是關鍵字,您應該爲插槽定義訪問器或讀取器。 – Svante

回答

1

我會根據這個format。這個想法是從您的arg-list構建一個格式字符串 。

我定義了一個輔助函數爲:

(defun make-format-string-and-args (arg-list) 
    (let ((symbols())) 
    (values (apply #'concatenate 'string 
        (mapcar (lambda (arg) 
          (ctypecase arg 
           (string 
           (cl-ppcre:regex-replace-all "~" arg "~~")) 
           (symbol 
           (push arg symbols) 
           "~a"))) 
          arg-list)) 
      (nreverse symbols)))) 

注意~必須format字符串,爲了逃避他們加倍。

打印宏本身然後就產生了mapcarformat的:

(defmacro print-table (stream arg-list time-info-list) 
    (let ((time-info (gensym))) 
    (multiple-value-bind (format-string arguments) 
     (make-format-string-and-args arg-list) 
     `(mapcar (lambda (,time-info) 
       (format ,stream ,format-string 
         ,@(mapcar (lambda (arg) 
            (list arg time-info)) 
            arguments))) 
       ,time-info-list))) 

然後你可以這樣調用:

(print-table *trace-output* 
      ("|" name "||" calls "|" second "\\") 
      my-time-info-list) 

請注意,您的代碼以下錯誤:

  • 您需要轉義\字符串。

  • Second已經是從common-lisp 包中導出的函數名稱。你不應該用通用函數來破壞它。

+0

謝謝你的幫助。我正在研究一個類似的想法:) –

0

首先,如果你正在使用宏(如果你使用的是函數,你可能不希望它在那裏)。其次,你是否想要在分隔符和值之間填充任何內容?第三,你可能更喜歡使用函數,而不是宏。

你似乎也在交替使用「數組」和「列表」。它們在Common Lisp中完全不同。有一些操作可以處理通用序列,但通常情況下,您會使用一種方法遍歷列表,另一種方法遍歷數組。

+0

是的,我仍然在學習宏,我不確定,但你是對的,一個報價是沒有必要的。 –

+0

對於填充,它應該是我沒有在示例中包含的一個選項。這個想法是,它可能不需要用戶。第三,我不確定函數和宏之間是什麼。我使用了單詞數組,因爲這是您在打印時得到的。我將在我的消息中編輯這個:) –

+0

@第三個人 - 當你打印它時你可能會得到一張桌子。 :) – Vatine

1

您需要更精確地滿足您的要求。宏和函數是不同的東西。數組和列表也不同。

我們需要遍歷TIME-INFO-LIST。所以這是第一個DOLIST

該表格有一行描述。說明中的每個項目都是插槽名稱或字符串。所以我們重複描述。這是第二個DOLIST。一個字符串只是打印。符號是插槽名稱,我們從當前的time-info實例中檢索插槽值。

(defun print-table (stream line-format-description time-info-list) 
    (dolist (time-info time-info-list) 
    (terpri stream) 
    (dolist (slot-or-string line-format-description) 
     (princ (etypecase slot-or-string 
       (string slot-or-string) 
       (symbol (slot-value time-info slot-or-string))) 
      stream)))) 

測試:

> (print-table *standard-output* 
       '("|" name "||" calls "|" second "\\") 
       (list (make-instance 'time-info 
            :name "foo" 
            :calls 100 
            :second 10) 
        (make-instance 'time-info 
            :name "bar" 
            :calls 20 
            :second 20))) 

|foo||100|10\ 
|bar||20|20\