From 5cdbb7e6b9dd0f7e925c1dfe7750c08a146bbee3 Mon Sep 17 00:00:00 2001
From: mehbark <terezi@pyrope.net>
Date: Mon, 24 Feb 2025 16:16:24 -0500
Subject: [PATCH] feat: `either`

---
 either.sls | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)
 create mode 100644 either.sls

diff --git a/either.sls b/either.sls
new file mode 100644
index 0000000..b59b1a8
--- /dev/null
+++ b/either.sls
@@ -0,0 +1,119 @@
+;; functional error handling with Either type
+;; initially written by claude 3.7!
+(library (meh either)
+  (export
+   either either?
+   left? right?
+   left-value right-value
+   left right
+   either-value
+   either-map
+   either-bind
+   either-fold
+   either->list
+
+   ;; syntax helpers
+   try-either
+   with-either
+   either-let)
+  (import (chezscheme)
+          (meh match)
+          (meh std))
+
+  ;; Core implementation using tagged records
+  (define-record-type either
+    (fields tag value)
+    (protocol
+     (lambda (new)
+       (lambda (tag value)
+         (unless (memq tag '(left right))
+           (assertion-violation 'make-either
+                               "Invalid tag, must be 'left or 'right"
+                               tag))
+         (new tag value)))))
+
+  ;; Constructors and predicates
+  (define (left value)
+    (make-either 'left value))
+
+  (define (right value)
+    (make-either 'right value))
+
+  (define (left? e)
+    (and (either? e) (eq? (either-tag e) 'left)))
+
+  (define (right? e)
+    (and (either? e) (eq? (either-tag e) 'right)))
+
+  ;; Accessors with safety checks
+  (define (left-value e)
+    (if (left? e)
+        (either-value e)
+        (assertion-violation 'left-value "Expected a Left value" e)))
+
+  (define (right-value e)
+    (if (right? e)
+        (either-value e)
+        (assertion-violation 'right-value "Expected a Right value" e)))
+
+  ;; Functional operations
+  (define (either-map f e)
+    (if (right? e)
+        (right (f (right-value e)))
+        e))
+
+  (define (either-bind e f)
+    (if (right? e)
+        (f (right-value e))
+        e))
+
+  (define (either-fold left-f right-f e)
+    (if (left? e)
+        (left-f (left-value e))
+        (right-f (right-value e))))
+
+  (define (either->list e)
+    (either-fold
+     (lambda (v) '())
+     (lambda (v) (list v))
+     e))
+
+  ;; Add pattern matching support
+  (define-record-equality! either)
+  (define-record-pattern! either)
+
+  ;; Define pattern expanders for left and right
+  (define-pattern (left pat) (either 'left pat))
+
+  (define-pattern (right pat) (either 'right pat))
+
+  ;; Exception handling helper - now with explicit condition handling
+  (define-syntax try-either
+    (syntax-rules ()
+      [(_ expr)
+       (guard (exn
+               [(condition? exn) (left exn)])
+              (right expr))]))
+
+  ;; Syntax for monadic composition
+  (define-syntax either-let
+    (syntax-rules ()
+      [(_ () expr) (right expr)]
+      [(_ ([var val]) expr)
+       (either-bind val (lambda (var) (right expr)))]
+      [(_ ([var val] [var2 val2] ...) expr)
+       (either-bind val
+                   (lambda (var)
+                     (either-let ([var2 val2] ...) expr)))]))
+
+  ;; Syntax for unwrapping either values with early return on error
+  (define-syntax with-either
+    (syntax-rules ()
+      [(_ default [pat expr])
+       (match expr
+         [(right pat) pat]
+         [_ default])]
+      [(_ default [pat expr] [pat2 expr2] ...)
+       (match expr
+         [(right pat) (with-either default [pat2 expr2] ...)]
+         [_ default])])))