Tagged Values
1 Overview
This package implements variants (tagged values) as the dual of Racket’s native multiple values, establishing a mathematical correspondence between programming constructs and set operations:
Product as Untagged Values
Racket’s values corresponds to Cartesian product (×), where (values v ...) represents an element of a product set. The isomorphism A ≅ A × 1 justifies treating v as (values v).
Sum as Tagged Values
The variant corresponds to disjoint union (+), where (variant #:tag n v ...) represents an element of a sum (coproduct) set. The isomorphism A ≅ A + 0 justifies treating (values v ...) as (variant #:tag 0 v ...).
2 API Reference
procedure
(inclusion n) → procedure?
n : natural?
> ((inclusion 0) 1 2 3)
(tag 0)
1
2
3
> ((inclusion 1) 1 2 3)
(tag 1)
1
2
3
> ((inclusion 1) 1 2 3 #:tag 1)
(tag 2)
1
2
3
procedure
(apply/variant proc v ... lst [#:tag n]) → any
proc : procedure? v : any/c lst : list? n : natural? = 0
> (apply/variant + 1 2 (list 3)) 6
> (apply/variant + 1 2 (list 3) #:tag 0) 6
> (apply/variant + 1 2 (list 3) #:tag 1) application: procedure does not accept keyword arguments
procedure: +
arguments...:
1
2
3
#:tag 1
> (apply/variant (λ (a b #:tag [n 0]) (cons (vector a b) n)) (list 1 2) #:tag 1) '(#(1 2) . 1)
procedure
(call-with-variant generator receiver) → any
generator : (-> any) receiver : procedure?
> (call-with-variant (λ () (variant 'a 'b)) cons) '(a . b)
> (call-with-variant (λ () (variant 'a 'b #:tag 0)) cons) '(a . b)
> (call-with-variant (λ () (variant 'a 'b #:tag 1)) cons) application: procedure does not accept keyword arguments
procedure: cons
arguments...:
'a
'b
#:tag 1
> (call-with-variant (λ () (variant 'a 'b)) (λ (a b #:tag [n 0]) (cons (vector a b) n))) '(#(a b) . 0)
> (call-with-variant (λ () (variant 'a 'b #:tag 1)) (λ (a b #:tag [n 0]) (cons (vector a b) n))) '(#(a b) . 1)
procedure
(compose/variant proc ...) → procedure?
proc : procedure?
Calling (compose/variant) returns variant, which acts as the identity element, so (compose/variant variant f variant) simply yields f.
> (define add1-tag (λ (x) (variant (add1 x) #:tag 1))) > (define unwrap (λ (#:tag [n 0] x) (cons x n))) > ((compose/variant unwrap add1-tag) 3) '(4 . 1)
> (compose/variant add1-tag variant) #<procedure:add1-tag>
> (compose/variant variant add1-tag) #<procedure:add1-tag>
procedure
(distributivity/column #:shape shape v ...) → any
shape : vector? v : any/c
This procedure follows the usual distributive law of multiplication over addition. As an illustration:
(a + b + c) × (d + e + f) ≅ a × d + b × d + c × d + a × e + b × e + c × e + a × f + b × f + c × f
> (distributivity/column #:shape #(3 3) 'a0 'a1 (tag 0) 'd0 'd1)
'a0
'a1
'd0
'd1
> (distributivity/column #:shape #(3 3) (tag 1) 'b0 'b1 (tag 0) 'd0 'd1)
(tag 1)
'b0
'b1
'd0
'd1
> (distributivity/column #:shape #(3 3) (tag 2) 'c0 'c1 (tag 0) 'd0 'd1)
(tag 2)
'c0
'c1
'd0
'd1
> (distributivity/column #:shape #(3 3) 'a0 'a1 (tag 1) 'e0 'e1)
(tag 3)
'a0
'a1
'e0
'e1
> (distributivity/column #:shape #(3 3) (tag 1) 'b0 'b1 (tag 1) 'e0 'e1)
(tag 4)
'b0
'b1
'e0
'e1
> (distributivity/column #:shape #(3 3) (tag 2) 'c0 'c1 (tag 1) 'e0 'e1)
(tag 5)
'c0
'c1
'e0
'e1
> (distributivity/column #:shape #(3 3) 'a0 'a1 (tag 2) 'f0 'f1)
(tag 6)
'a0
'a1
'f0
'f1
> (distributivity/column #:shape #(3 3) (tag 1) 'b0 'b1 (tag 2) 'f0 'f1)
(tag 7)
'b0
'b1
'f0
'f1
> (distributivity/column #:shape #(3 3) (tag 2) 'c0 'c1 (tag 2) 'f0 'f1)
(tag 8)
'c0
'c1
'f0
'f1
procedure
(distributivity/row #:shape shape v ...) → any
shape : vector? v : any/c
(a + b + c) × (d + e + f) ≅ a × d + a × e + a × f + b × d + b × e + b × f + c × d + c × e + c × f
> (distributivity/row #:shape #(3 3) 'a0 'a1 (tag 0) 'd0 'd1)
'a0
'a1
'd0
'd1
> (distributivity/row #:shape #(3 3) 'a0 'a1 (tag 1) 'e0 'e1)
(tag 1)
'a0
'a1
'e0
'e1
> (distributivity/row #:shape #(3 3) 'a0 'a1 (tag 2) 'f0 'f1)
(tag 2)
'a0
'a1
'f0
'f1
> (distributivity/row #:shape #(3 3) (tag 1) 'b0 'b1 (tag 0) 'd0 'd1)
(tag 3)
'b0
'b1
'd0
'd1
> (distributivity/row #:shape #(3 3) (tag 1) 'b0 'b1 (tag 1) 'e0 'e1)
(tag 4)
'b0
'b1
'e0
'e1
> (distributivity/row #:shape #(3 3) (tag 1) 'b0 'b1 (tag 2) 'f0 'f1)
(tag 5)
'b0
'b1
'f0
'f1
> (distributivity/row #:shape #(3 3) (tag 2) 'c0 'c1 (tag 0) 'd0 'd1)
(tag 6)
'c0
'c1
'd0
'd1
> (distributivity/row #:shape #(3 3) (tag 2) 'c0 'c1 (tag 1) 'e0 'e1)
(tag 7)
'c0
'c1
'e0
'e1
> (distributivity/row #:shape #(3 3) (tag 2) 'c0 'c1 (tag 2) 'f0 'f1)
(tag 8)
'c0
'c1
'f0
'f1
syntax
(let*-variant ([kw-formals rhs-expr] ...) body ...+)
kw-formals = (arg ...) | (arg ...+ . rest-id) | rest-id arg = id | [id default-expr] | #:tag id | #:tag [id default-expr]
> (let*-variant ([v* (variant 1 2 3)]) v*) '(1 2 3)
> (let*-variant ([(v . v*) (variant 1 2 3)]) (cons v* v)) '((2 3) . 1)
> (let*-variant ([(v . v*) (variant 1 2 3 #:tag 0)]) (cons v* v)) '((2 3) . 1)
> (let*-variant ([(v . v*) (variant 1 2 3 #:tag 1)]) (cons v* v)) application: procedure does not accept keyword arguments
procedure: ...gs/variant/main.rkt:167:8
arguments...:
1
2
3
#:tag 1
> (let*-variant ([(#:tag n v . v*) (variant 1 2 3 #:tag 1)]) (cons (cons v* v) n)) '(((2 3) . 1) . 1)
> (let*-variant ([(#:tag [n 0] v . v*) (variant 1 2 3)]) (cons (cons v* v) n)) '(((2 3) . 1) . 0)
> (let*-variant ([(#:tag n v . v*) (variant 1 2 3)]) (cons (cons v* v) n)) application: required keyword argument not supplied
procedure: ...kgs/variant/main.rkt:167:8
required keyword: #:tag
arguments...:
1
2
3
> (let*-variant ([(#:tag n v . v*) (variant 1 2 3 #:tag 0)]) (cons (cons v* v) n)) application: required keyword argument not supplied
procedure: ...kgs/variant/main.rkt:167:8
required keyword: #:tag
arguments...:
1
2
3
syntax
(define-variant kw-formals expr)
> (let () (define-variant v* (variant 1 2 3)) v*) '(1 2 3)
> (let () (define-variant (v . v*) (variant 1 2 3)) (cons v* v)) '((2 3) . 1)
> (let () (define-variant (v . v*) (variant 1 2 3 #:tag 0)) (cons v* v)) '((2 3) . 1)
> (let () (define-variant (v . v*) (variant 1 2 3 #:tag 1)) (cons v* v)) application: procedure does not accept keyword arguments
procedure: ...gs/variant/main.rkt:167:8
arguments...:
1
2
3
#:tag 1
> (let () (define-variant (#:tag n v . v*) (variant 1 2 3 #:tag 1)) (cons (cons v* v) n)) '(((2 3) . 1) . 1)
> (let () (define-variant (#:tag [n 0] v . v*) (variant 1 2 3)) (cons (cons v* v) n)) '(((2 3) . 1) . 0)
> (let () (define-variant (#:tag n v . v*) (variant 1 2 3)) (cons (cons v* v) n)) application: required keyword argument not supplied
procedure: ...kgs/variant/main.rkt:167:8
required keyword: #:tag
arguments...:
1
2
3
> (let () (define-variant (#:tag n v . v*) (variant 1 2 3 #:tag 0)) (cons (cons v* v) n)) application: required keyword argument not supplied
procedure: ...kgs/variant/main.rkt:167:8
required keyword: #:tag
arguments...:
1
2
3