Assoc lens

Association lists are the default struct in Lisp. I don't use them as much as I should; I usually reach for simple cons lists to collect multiple values when folding etc. That's not good. I spun up some helper syntax for these records to encourage their use.

(define-syntax λ (syntax-rules () ((_ . α) (lambda . α))))
(define-syntax ∃ (syntax-rules () ((_ . α) (let* . α))))
(define-syntax ? (syntax-rules () ((_ . α) (if . α))))
(define-syntax ← (syntax-rules ()
 ((_ ((α ω ...) ...)) (begin (define α ω ...) ...))
 ((_ . α) (define . α))))
(← ((↑ car) (↓ cdr) (⇒ foldr) (⊂ cons) (≡ equal?) (∅ '()) (∈ assoc) ($ apply)))
(← (∈∈ α ω) (↑ (↓ (∈ α ω))))
(← (∈$ α f ω) (∃ ((A (↑ ω)) (Ω (↓ ω))) (? (≡ α A) `(,α ,($ f Ω)) ω)))
(← (∈⇒ α f ω) (⇒ (λ (x acc) (⊂ (∈$ α f x) acc)) ∅ ω))

Deep access

is a synonym for assoc. It returns an entire matching record row.

(∈ 'Ω '((A 2) (Ω 4)))
  (Ω 4)

This is useful, but sometimes, oftentimes, we want the value itself.

(← (∈∈ α ω) (↑ (↓ (∈ α ω))))
(∈∈ 'Ω '((A 2) (Ω 4)))
  4

Over

I wanted a function to modify one row of the record, then return the entire thing, much like the over lens in Haskell. This was accomplished in two functions. The first of which is the "row apply" procedure, which only applies f to a row if its key is a match. It returns an unmodified row otherwise.

(← (∈$ α f ω) (∃ ((A (↑ ω)) (Ω (↓ ω))) (? (≡ α A) `(,α ,($ f Ω)) ω)))
(∈$ 'Ω (λ (α) (* α α)) '(A 2))
  (A 2)
(∈$ 'Ω (λ (α) (* α α)) '(Ω 4))
  (Ω 16)

This is used by the full "over" function, which folds ∈$ across a record.

(← (∈⇒ α f ω) (⇒ (λ (x acc) (⊂ (∈$ α f x) acc)) ∅ ω))
(∈⇒ 'Ω (λ (α) (* α α)) '((A 2) (Ω 4)))
  ((A 2) (Ω 16))

This composes nicely with multiple operations.

(∈⇒ 'A (λ (α) (* α α)) (∈⇒ 'Ω (λ (α) (* α α)) '((A 2) (Ω 4))))
  ((A 4) (Ω 16))

Maybe some implementations have existing syntax for this. Mine's better.