;; Condition-Restart Example in Common Lisp
;; Rangarajan Krishnamoorthy, March 5, 2026

;; A simple condition: we encountered a negative number
(define-condition negative-number (error)
  ((value :initarg :value :reader negative-number-value))
  (:report (lambda (c stream)
             (format stream "Encountered negative number: ~A"
                     (negative-number-value c)))))

;; This function processes a single number.
;; It knows HOW to recover (use absolute value, or use zero),
;; but it doesn't decide WHICH recovery to use.
(defun process-number (n)
  (restart-case
      (if (minusp n)
          (error 'negative-number :value n)
          (* n 2))
    (use-absolute-value ()
      :report "Use the absolute value instead."
      (* (abs n) 2))
    (use-zero ()
      :report "Use zero instead."
      0)))

;; This function processes a list of numbers. 
;; It knows nothing about errors.
(defun process-list (numbers)
  (mapcar #'process-number numbers))

;; Top-level functions
;; These decide policy to follow

;; Policy A: always use absolute value
(defun run-with-abs (numbers)
  (handler-bind
      ((negative-number
        (lambda (c)
          (declare (ignore c))
          (invoke-restart 'use-absolute-value))))
    (process-list numbers)))

;; Policy B: always substitute zero
(defun run-with-zero (numbers)
  (handler-bind
      ((negative-number
        (lambda (c)
          (declare (ignore c))
          (invoke-restart 'use-zero))))
    (process-list numbers)))


;;;-----------------
; (run-with-abs '(1 -2 3 -4 5))
; (run-with-zero '(1 -2 3 -4 5))
; (process-list '(1 -2 3 -4 5))