LISP - Penanganan Error

Dalam terminologi LISP umum, pengecualian disebut kondisi.

Faktanya, kondisi lebih umum daripada pengecualian dalam bahasa pemrograman tradisional, karena a condition mewakili setiap kejadian, kesalahan, atau tidak, yang mungkin mempengaruhi berbagai tingkat tumpukan panggilan fungsi.

Mekanisme penanganan kondisi di LISP, menangani situasi tersebut sedemikian rupa sehingga kondisi digunakan untuk memberi sinyal peringatan (misalnya dengan mencetak peringatan) sementara kode tingkat atas pada tumpukan panggilan dapat melanjutkan pekerjaannya.

Sistem penanganan kondisi di LISP memiliki tiga bagian -

  • Menandakan suatu kondisi
  • Penanganan kondisi
  • Mulai ulang prosesnya

Menangani Kondisi

Mari kita ambil contoh penanganan kondisi yang timbul dari kondisi bagi dengan nol, untuk menjelaskan konsepnya di sini.

Anda perlu mengambil langkah-langkah berikut untuk menangani suatu kondisi -

  • Define the Condition - "Kondisi adalah objek yang kelasnya menunjukkan sifat umum dari kondisi dan data contoh yang membawa informasi tentang rincian keadaan tertentu yang mengarah ke kondisi yang diberi sinyal".

    Makro definisikan kondisi digunakan untuk menentukan kondisi, yang memiliki sintaks berikut -

(define-condition condition-name (error)
   ((text :initarg :text :reader text))
)
  • Objek kondisi baru dibuat dengan makro MAKE-CONDITION, yang menginisialisasi slot kondisi baru berdasarkan :initargs argumen.

Dalam contoh kami, kode berikut mendefinisikan kondisi -

(define-condition on-division-by-zero (error)
   ((message :initarg :message :reader message))
)
  • Writing the Handlers- pengendali kondisi adalah kode yang digunakan untuk menangani kondisi yang ditandai di atasnya. Ini umumnya ditulis di salah satu fungsi tingkat yang lebih tinggi yang memanggil fungsi kesalahan. Ketika sebuah kondisi ditandai, mekanisme pensinyalan mencari penangan yang sesuai berdasarkan kelas kondisi tersebut.

    Setiap penangan terdiri dari -

    • Type specifier, yang menunjukkan jenis kondisi yang dapat ditangani
    • Fungsi yang membutuhkan satu argumen, kondisi

    Ketika suatu kondisi diberi sinyal, mekanisme pensinyalan menemukan penangan yang paling baru dibuat yang kompatibel dengan tipe kondisi dan memanggil fungsinya.

    Makro handler-casemenetapkan penangan kondisi. Bentuk dasar handler-case -

(handler-case expression error-clause*)

Di mana, setiap klausa kesalahan berbentuk -

condition-type ([var]) code)
  • Restarting Phase

    Ini adalah kode yang benar-benar memulihkan program Anda dari kesalahan, dan penangan kondisi kemudian dapat menangani kondisi dengan menjalankan restart yang sesuai. Kode restart umumnya ditempatkan di fungsi tingkat menengah atau tingkat rendah dan penangan kondisi ditempatkan di tingkat atas aplikasi.

    Itu handler-bindmakro memungkinkan Anda untuk menyediakan fungsi restart, dan memungkinkan Anda untuk melanjutkan di fungsi tingkat yang lebih rendah tanpa melepaskan tumpukan panggilan fungsi. Dengan kata lain, aliran kendali akan tetap berada di fungsi level bawah.

    Bentuk dasar handler-bind adalah sebagai berikut -

(handler-bind (binding*) form*)

Di mana setiap pengikatan adalah daftar berikut -

  • tipe kondisi
  • fungsi penangan dari satu argumen

Itu invoke-restart macro menemukan dan memanggil fungsi restart terikat terbaru dengan nama yang ditentukan sebagai argumen.

Anda dapat memulai ulang berkali-kali.

Contoh

Dalam contoh ini, kami mendemonstrasikan konsep di atas dengan menulis fungsi bernama fungsi-pembagian, yang akan membuat kondisi kesalahan jika argumen pembagi adalah nol. Kami memiliki tiga fungsi anonim yang menyediakan tiga cara untuk keluar darinya - dengan mengembalikan nilai 1, dengan mengirimkan pembagi 2 dan menghitung ulang, atau dengan mengembalikan 1.

Buat file kode sumber baru bernama main.lisp dan ketikkan kode berikut di dalamnya.

(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."))

Saat Anda menjalankan kode, ia mengembalikan hasil berikut -

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

Selain 'Sistem Kondisi', seperti yang dibahas di atas, LISP Umum juga menyediakan berbagai fungsi yang mungkin dipanggil untuk menandakan kesalahan. Penanganan kesalahan, ketika diberi tanda, bagaimanapun, bergantung pada implementasi.

Fungsi Pemberian Sinyal Kesalahan di LISP

Tabel berikut menyediakan fungsi yang umum digunakan memberi sinyal peringatan, jeda, kesalahan non-fatal dan fatal.

Program pengguna menentukan pesan kesalahan (string). Fungsi memproses pesan ini dan mungkin / mungkin tidak menampilkannya kepada pengguna.

Pesan kesalahan harus dibuat dengan menerapkan format fungsi, tidak boleh berisi karakter baris baru di awal atau akhir, dan tidak perlu menunjukkan kesalahan, karena sistem LISP akan menangani ini sesuai dengan gaya yang disukai.

Sr.No. Fungsi dan Deskripsi
1

error format-string & rest args

Ini menandakan kesalahan fatal. Tidak mungkin melanjutkan kesalahan semacam ini; dengan demikian kesalahan tidak akan pernah kembali ke pemanggilnya.

2

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

Ini menandakan kesalahan dan memasuki debugger. Namun, ini memungkinkan program dilanjutkan dari debugger setelah mengatasi kesalahan.

3

warn format-string & rest args

itu mencetak pesan kesalahan tetapi biasanya tidak masuk ke debugger

4

break& format-string opsional & argumen istirahat

Ini mencetak pesan dan langsung masuk ke debugger, tanpa membiarkan kemungkinan intersepsi oleh fasilitas penanganan kesalahan yang diprogram

Contoh

Dalam contoh ini, fungsi faktorial menghitung faktorial sebuah angka; Namun, jika argumennya negatif, hal itu menimbulkan kondisi kesalahan.

Buat file kode sumber baru bernama main.lisp dan ketikkan kode berikut di dalamnya.

(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))

Saat Anda menjalankan kode, ia mengembalikan hasil berikut -

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