2017-05-15 52 views
3

所以考慮下面的代碼:HANDLER-CASE替代它不是宏觀

(define-condition some-condition (error) nil) 

(defmethod print-object ((obj some-condition) stream) 
    (format stream "HELLO THERE")) 

(defmacro error-report-test-aux (fn-to-cause-error error-type-to-catch fn-to-handle-error expected-message) 
    `(let ((result-message 
      (handler-case (funcall ,fn-to-cause-error) 
      (,error-type-to-catch (e) (funcall ,fn-to-handle-error e))))) 
    (assert (string= result-message 
         ,expected-message)) 
    t)) 

我可以用它像這樣:

(error-report-test-aux (lambda() (error 'some-condition)) 
         some-condition 
         #'princ-to-string 
         "HELLO THERE") 

但我想讓error-report-test-aux一個函數,而不是宏,這樣我就可以在變量中傳遞一個條件類型。

要簡單地寫defun,而不是defmacro並刪除反引號和逗號不起作用,因爲handler-case是宏觀,它不評估error-type-to-catch

我的問題是:有沒有像handler-case那樣會評估它的參數(特別是條件類型參數)?

+0

我不認爲將'nil'作爲'stream'傳遞給'print-object'是符合規範的代碼。你可能打算在那裏使用'princ-to-string'而不是'lambda'。 – sds

+1

你可以嘗試用'HANDLER-BIND'爲任何'CONDITION'建立一個處理程序,在那裏你檢查條件是否是正確的類型,如果不正確則拒絕處理。 – jkiiski

+1

@sds您的評論讓我讀了一堆CLHS。現在我知道更多,謝謝。 –

回答

5

是的,沒有:-)

沒有您的具體問題

沒有標準功能,將你想要做什麼,因爲捕捉錯誤,需要建立綁定,人們通常要綁定常數符號(如let/let*),因爲它更容易優化。

可能考慮使用handler-bind然後拒絕處理「無趣」的條件(在評論@jkiiski的建議)創建一個「通用」的處理程序,但我不知道是否適合您的具體要求(未經測試! ):

(defun error-report-test-aux (fn-to-cause-error error-type-to-catch expected-message) 
    (catch 'trap 
    (handler-bind ((error 
        (lambda (condition) 
         (when (typep condition error-type-to-catch) 
         (throw 'trap (string= (princ-to-string condition) 
               expected-message)))))) 
     (funcall fn-to-cause-error)))) 

,實現特定的

IF您實現IM通過綁定一個內部全局變量來獲取handler-case/handler-bind,您可以使用progv自己綁定它,從而實現您的error-report-test-aux作爲函數。

這可能不是最好的想法(您的代碼會嵌入到特定的實現中)。

,還挺

您可以使用這一事實some-condition名稱的CLOS類,並使用,而不是宏觀的通用功能。