Errors in Lisp

;; In Lisp, it's common to use multiple values for returning results and errors.
;; This approach is similar to Go's explicit error returns.

;; Define a function that may return an error
(defun f (arg)
  (if (= arg 42)
      (values -1 "can't work with 42")  ; Return multiple values: result and error
      (values (+ arg 3) nil)))          ; No error, return result and nil

;; Define some global error conditions
(define-condition out-of-tea-error (error) ())
(define-condition power-error (error) ())

;; Function that may signal an error
(defun make-tea (arg)
  (cond ((= arg 2) (error 'out-of-tea-error :message "no more tea available"))
        ((= arg 4) (error 'power-error :message "can't boil water"))
        (t nil)))

;; Main function
(defun main ()
  ;; Test f function
  (dolist (i '(7 42))
    (multiple-value-bind (result error) (f i)
      (if error
          (format t "f failed: ~A~%" error)
          (format t "f worked: ~A~%" result))))

  ;; Test make-tea function
  (dotimes (i 5)
    (handler-case
        (progn
          (make-tea i)
          (format t "Tea is ready!~%"))
      (out-of-tea-error ()
        (format t "We should buy new tea!~%"))
      (power-error ()
        (format t "Now it is dark.~%"))
      (error (e)
        (format t "unknown error: ~A~%" e)))))

;; Run the main function
(main)

In Lisp, error handling is typically done using conditions and handlers, which is somewhat different from Go’s approach. Here’s an explanation of the key concepts:

  1. Multiple value returns: Lisp can return multiple values from a function, which we use to simulate Go’s result and error returns.

  2. Conditions: These are similar to Go’s error types. We define custom conditions for specific error cases.

  3. Error signaling: Instead of returning errors, Lisp functions signal errors using the error function.

  4. Error handling: Lisp uses handler-case to catch and handle different types of errors, similar to Go’s if err != nil checks and type assertions.

The f function returns multiple values: the result and an error string (or nil if no error). The make-tea function signals errors using custom condition types.

In the main function, we use multiple-value-bind to capture both the result and error from f. For make-tea, we use handler-case to catch and handle different error conditions.

This Lisp code demonstrates error handling patterns that are idiomatic to the language while maintaining the spirit of explicit error handling from the original Go example.