Errors in Racket

In Racket, error handling is typically done using exceptions, which is different from Go’s approach of returning explicit error values. However, we can simulate a similar pattern using option types and custom structs. Here’s how we might implement the example:

#lang racket

(require racket/format)

;; Define a custom struct for errors
(struct custom-error (message) #:transparent)

;; Function that might produce an error
(define (f arg)
  (if (= arg 42)
      (values #f (custom-error "can't work with 42"))
      (values (+ arg 3) #f)))

;; Define sentinel errors
(define ErrOutOfTea (custom-error "no more tea available"))
(define ErrPower (custom-error "can't boil water"))

;; Function that uses sentinel errors
(define (make-tea arg)
  (cond
    [(= arg 2) ErrOutOfTea]
    [(= arg 4) (custom-error (~a "making tea: " (custom-error-message ErrPower)))]
    [else #f]))

;; Main function
(define (main)
  ;; Test f function
  (for ([i (in-list '(7 42))])
    (define-values (result error) (f i))
    (if error
        (printf "f failed: ~a\n" (custom-error-message error))
        (printf "f worked: ~a\n" result)))
  
  ;; Test make-tea function
  (for ([i (in-range 5)])
    (define error (make-tea i))
    (cond
      [(not error) (printf "Tea is ready!\n")]
      [(equal? error ErrOutOfTea) (printf "We should buy new tea!\n")]
      [(string-contains? (custom-error-message error) (custom-error-message ErrPower))
       (printf "Now it is dark.\n")]
      [else (printf "unknown error: ~a\n" (custom-error-message error))])))

;; Run the main function
(main)

This Racket code simulates Go’s error handling pattern:

  1. We define a custom-error struct to represent errors.

  2. The f function returns multiple values: the result and an error (if any).

  3. We define sentinel errors using our custom-error struct.

  4. The make-tea function demonstrates the use of sentinel errors and error wrapping.

  5. In the main function, we check for errors using conditional statements, similar to Go’s if err != nil pattern.

  6. We use equal? and string-contains? to check for specific errors, simulating Go’s errors.Is functionality.

To run this program, save it to a file (e.g., errors.rkt) and execute it using the Racket interpreter:

$ racket errors.rkt
f worked: 10
f failed: can't work with 42
Tea is ready!
Tea is ready!
We should buy new tea!
Tea is ready!
Now it is dark.

This Racket implementation provides a similar structure and behavior to the original Go code, while adapting to Racket’s language features and idioms.