鍍金池/ 教程/ Java/ LISP - 錯(cuò)誤處理
LISP - 樹(shù)
LISP - 錯(cuò)誤處理
LISP - 謂詞
LISP - 決策
LISP - 變量
LISP - 數(shù)組
LISP - 對(duì)象系統(tǒng)(CLOS)
LISP - 輸入和輸出
Lisp教程
LISP - 數(shù)字
LISP - 循環(huán)
LISP - 常量
LISP - 集合
LISP - 字符
LISP - 程序結(jié)構(gòu)
LISP - 文件I/O
LISP - 哈希表
LISP - 宏
LISP - 數(shù)據(jù)類型
LISP - 包
LISP - 符號(hào)
LISP - 運(yùn)算符
LISP - 基本語(yǔ)法
LISP - 函數(shù)
LISP - 向量
LISP - 結(jié)構(gòu)
LISP - 概述介紹

LISP - 錯(cuò)誤處理

面向?qū)ο蟮腻e(cuò)誤處理- LISP條件系統(tǒng)

在Common Lisp的術(shù)語(yǔ)中,異常被稱為條件。

事實(shí)上,條件比在傳統(tǒng)編程語(yǔ)言的異常更為普遍,因?yàn)橐粋€(gè)條件表示任何事件,錯(cuò)誤與否,這可能會(huì)影響各級(jí)函數(shù)調(diào)用堆棧。

在LISP狀態(tài)處理機(jī)制,處理的條件是用來(lái)警告信號(hào)(例如通過(guò)打印一個(gè)警告),而在調(diào)用堆棧的上層代碼可以繼續(xù)工作,這樣的情況下以這樣一種方式。

條件處理系統(tǒng)中LISP有三個(gè)部分:

  • 信號(hào)的條件

  • 處理?xiàng)l件

  • 重啟進(jìn)程

處理一個(gè)條件

讓我們處理由除零所產(chǎn)生的條件的例子,在這里解釋這些概念。

需要處理的條件如下步驟:

  1. 定義條件 - “條件是一個(gè)對(duì)象,它的類表示條件的一般性質(zhì),其實(shí)例數(shù)據(jù)進(jìn)行有關(guān)的特殊情況,導(dǎo)致被示意條件的細(xì)節(jié)信息”。

    定義條件的宏用于定義一個(gè)條件,它具有以下語(yǔ)法:

    (define-condition condition-name (error)
      ((text :initarg :text :reader text)))

    :initargs 參數(shù),新的條件對(duì)象與MAKE-CONDITION 宏,它初始化的基礎(chǔ)上,新的條件下的插槽中創(chuàng)建的。

    在我們的例子中,下面的代碼定義的條件:

    (define-condition on-division-by-zero (error)
       ((message :initarg :message :reader message)))
    
  2. 編寫(xiě)處理程序 - 條件處理程序是用于處理信號(hào)的條件在其上的代碼。它一般寫(xiě)在調(diào)用該函數(shù)出問(wèn)題的上級(jí)功能之一。當(dāng)條件信號(hào)發(fā)生時(shí),該信號(hào)轉(zhuǎn)導(dǎo)機(jī)制中搜索基于所述條件的類合適的處理器。

    每個(gè)處理程序包括:

    • 類型說(shuō)明符,它指示條件,它可以處理的類型

    • 一個(gè)函數(shù),它接受一個(gè)參數(shù)條件

    當(dāng)條件獲得信號(hào),該信號(hào)機(jī)制發(fā)現(xiàn)最近建立的處理程序與條件類型兼容,并調(diào)用它的函數(shù)。

    宏處理程序的情況建立了一個(gè)條件處理程序。一個(gè)處理程序的 handler-case 形式:

    (handler-case expression
      error-clause*)

    那么,每個(gè)error從句的形式為:

    condition-type ([var]) code)
  3. 重新啟動(dòng)階段

    這是真正從錯(cuò)誤的代碼中恢復(fù)程序,條件處理程序可以通過(guò)調(diào)用一個(gè)適當(dāng)?shù)闹貑⑻幚淼臈l件。重啟代碼一般是放置在中層或底層函數(shù)和條件處理程序被放置到應(yīng)用程序的上層。

    handler-bind宏允許提供一個(gè)重啟功能,并允許繼續(xù)在較低級(jí)的功能,無(wú)需解除函數(shù)的調(diào)用堆棧。換句話說(shuō),控制流將仍然處于較低水平的功能。

    handler-bind的基本形式如下:

    (handler-bind (binding*) form*)

    其中每個(gè)綁定如以下列表:

    • 條件類型

    • 一個(gè)參數(shù)的處理函數(shù)

    invoke-restart宏查找并調(diào)用具有指定名稱作為參數(shù)最近綁定重啟功能。

    可以有多個(gè)重新啟動(dòng)。

示例

在這個(gè)例子中,我們演示了上述概念通過(guò)寫(xiě)一個(gè)名為劃分功能函數(shù),則會(huì)創(chuàng)建錯(cuò)誤條件,如果除數(shù)參數(shù)為零。我們有三個(gè)匿名的功能,提供三種方式來(lái)出它 - 通過(guò)返回一個(gè)值1,通過(guò)發(fā)送一個(gè)除數(shù)2和重新計(jì)算,或通過(guò)返回1。

創(chuàng)建一個(gè)名為main.lisp一個(gè)新的源代碼文件,并在其中輸入如下代碼:

(define-condition on-division-by-zero (error)
   ((message :initarg :message :reader message)))
   
(defun handle-infinity ()
   (restart-case
       (let ((result 0))
         (setf result (division-function 10 0))
         (format t "Value: ~a~%" result))
     (just-continue () nil)))
     
 (defun division-function (value1 value2)
   (restart-case
       (if (/= value2 0)
           (/ value1 value2)
           (error 'on-division-by-zero :message "denominator is zero"))

     (return-zero () 0)
     (return-value (r) r)
     (recalc-using (d) (division-function value1 d))))

 (defun high-level-code ()
   (handler-bind
       ((on-division-by-zero
         #'(lambda (c)
             (format t "error signaled: ~a~%" (message c))
             (invoke-restart 'return-zero)))
     (handle-infinity))))

   (handler-bind
       ((on-division-by-zero
         #'(lambda (c)
             (format t "error signaled: ~a~%" (message c))
             (invoke-restart 'return-value 1))))
     (handle-infinity))

   (handler-bind
       ((on-division-by-zero
         #'(lambda (c)
             (format t "error signaled: ~a~%" (message c))
             (invoke-restart 'recalc-using 2))))
     (handle-infinity))

   (handler-bind
       ((on-division-by-zero
         #'(lambda (c)
             (format t "error signaled: ~a~%" (message c))
             (invoke-restart 'just-continue))))
     (handle-infinity))

   (format t "Done."))

當(dāng)執(zhí)行代碼,它返回以下結(jié)果:

error signaled: denominator is zero
Value: 1
error signaled: denominator is zero
Value: 5
error signaled: denominator is zero
Done.

除了“系統(tǒng)狀態(tài)”,如上文所討論,普通的LISP還提供了各種功能,其可被稱為信令錯(cuò)誤。當(dāng)信號(hào)實(shí)現(xiàn)相關(guān)處理錯(cuò)誤。

LISP的錯(cuò)誤信號(hào)功能

下表提供了常用功能的信令警告,休息,非致命和致命的錯(cuò)誤。

用戶程序指定一個(gè)錯(cuò)誤信息(字符串)。該函數(shù)處理這個(gè)消息,并且可能/可能不會(huì)顯示給用戶。

錯(cuò)誤信息應(yīng)該通過(guò)應(yīng)用的格式化功能進(jìn)行構(gòu)造,不應(yīng)該在開(kāi)頭或結(jié)尾包含一個(gè)換行符,也無(wú)需指明錯(cuò)誤,如LISP系統(tǒng)將根據(jù)其喜好的樣式利用這些服務(wù)。

SL No. 函數(shù)和說(shuō)明
1

error format-string &rest args

它標(biāo)志著一個(gè)致命的錯(cuò)誤。這是不可能從這種錯(cuò)誤的繼續(xù);這樣的錯(cuò)誤將永遠(yuǎn)不會(huì)返回到其調(diào)用者。

2

cerror continue-format-string error-format-string &rest args

它發(fā)出錯(cuò)誤信號(hào),并進(jìn)入調(diào)試器。但是,它允許程序從調(diào)試器解決錯(cuò)誤之后繼續(xù)。

3

warn format-string &rest args

它打印一條錯(cuò)誤消息,但一般不會(huì)進(jìn)入調(diào)試

4

break &optional format-string &rest args

它打印的消息,并直接進(jìn)入調(diào)試器,而不允許攔截由編程錯(cuò)誤處理設(shè)施的任何可能性

示例

在這個(gè)例子中,階乘函數(shù)計(jì)算一個(gè)數(shù)階乘;但是,如果參數(shù)為負(fù),它拋出一個(gè)錯(cuò)誤條件。

創(chuàng)建一個(gè)名為main.lisp一個(gè)新的源代碼文件,并在其中輸入如下代碼:

(defun factorial (x)
   (cond ((or (not (typep x 'integer)) (minusp x))
          (error "~S is a negative number." x))
         ((zerop x) 1)
         (t (* x (factorial (- x 1))))))
         
(write(factorial 5))
(terpri)
(write(factorial -1))

當(dāng)執(zhí)行代碼,它返回以下結(jié)果:

120
*** - -1 is a negative number.

上一篇:LISP - 集合下一篇:LISP - 決策