2015-04-30 12 views
1

我試圖格式化任意表達式,例如(+ 2 3),同時結果爲5將表達式及其結果同時格式化爲無評估

我有以下幾點:

(defun expr-and-result (expr) 
    (format t "~a returns ~a~%" expr (eval expr))) 

CL-USER> (expr-and-result '(+ 2 3)) 
    (+ 2 3) returns 5 

雖然這是一個簡單的事情,通過使用eval,我很好奇,如果這種效應可以沒有它來完成(因爲我聽說過很多這EVAL是要避免) 。

據我所知,引用參數是必要的,因爲否則給定的表達式將作爲調用expr-and-result的第一步進行評估,並且只有其結果可以在expr-and-result內使用。因此,任何可能的解決方案都需要引用輸入,對嗎?

我想到了一些關於宏的問題,但我覺得這是我尋找的錯誤方法。

編輯:我的意圖是建立一個簡單的測試套件,如:

(progn 
    (mapcar #'expr-and-result 
      '((= (my-remainder 7 3) 1) 
      (= (my-remainder 7 3) 2))) 
    'end-of-tests) 

Outputs: 
(= (MY-REMAINDER 7 3) 1) returns T 
(= (MY-REMAINDER 7 3) 2) returns NIL 
END-OF-TESTS 

閱讀保羅的意見後,似乎eval是我的目的,最短和乾淨的解決方案。

+1

這取決於你打算如何使用它。如果你正在開發一個詳細的調試宏,那麼你應該生成'(format ...)'表達式,引用第一個參數而不是第二個參數。如果這是用於REPL或某個解釋器,那就很好。除了你真的想觀察編譯的副作用或執行'expr'幾次之外,還有一個編譯的替代方法是'''(funcall(compile nil'(lambda(),expr)))'''不需要這個。 – acelent

+0

@PauloMadeira感謝您的評論,我的目的是創建一個簡潔的測試套件,用於將功能輸出與預期結果進行比較。 (我編輯了我的問題)。生成一個'format'表達式聽起來像是過度殺毒,儘管我覺得它會比eval更靈活。 –

+1

不要重新發明輪子:http://cliki.net/test%20framework – Sylwester

回答

3

下面是一個簡單的宏:

(defmacro exec-and-report (form) 
    `(format t "~S returns ~S~%" ',form ,form)) 
(macroexpand '(exec-and-report (+ 1 2))) 
==> 
(FORMAT T "~S returns ~S~%" '(+ 1 2) (+ 1 2)) ; 
T 
(exec-and-report (+ 1 2)) 
==> 
(+ 1 2) returns 3 
NIL 

PS。我第二@西爾維斯特的建議not to reinvent the wheel

+2

我會(親自)在'LET'中包裝它並返回值。這可以讓它作爲一個參數來堅持它(但是,嘿,這是完全正確的)。 – Vatine