Tagged Values
1 Overview
2 API Reference
tag
variant
inclusion
apply/  variant
call-with-variant
compose/  variant
distributivity/  column
distributivity/  row
let*-variant
define-variant
8.17.0.6

Tagged Values🔗ℹ

 (require variant) package: variant

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🔗ℹ

struct

(struct tag (number)
    #:extra-constructor-name make-tag
    #:transparent)
  number : natural?
A structure type for tags.

Examples:
> (tag 1)

(tag 1)

> (tag 0)

(tag 0)

> (tag -1)

tag: contract violation

  expected: natural?

  given: -1

procedure

(variant v ... [#:tag n])  any

  v : any/c
  n : natural? = 0
A variant-aware version of values. Constructs tagged values. When n is 0 (default), returns plain values.

Examples:
> (variant 1 2 3)

1

2

3

> (variant 1 2 3 #:tag 0)

1

2

3

> (variant 1 2 3 #:tag 1)

(tag 1)

1

2

3

procedure

(inclusion n)  procedure?

  n : natural?
Adds n to the incoming tag and returns a tagged values.

Examples:
> ((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
A variant-aware version of apply. It calls proc on (list* v ... lst), passing #:tag n as a normal keyword argument when n is non-zero.

Examples:
> (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?
A variant-aware version of call-with-values. Applies receiver to the variant produced by generator.

Examples:
> (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?
A variant-aware version of compose. Composes procedures with call-with-variant so that tags are forwarded between them. The rightmost procedure is applied first.

Calling (compose/variant) returns variant, which acts as the identity element, so (compose/variant variant f variant) simply yields f.

Examples:
> (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
Distributes nested sums over products according to shape. Each argument must start with a tag (including (tag 0)) indicating which option was chosen. The resulting variant is tagged with the combined index in column-major order.

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

Examples:
> (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
Similar to distributivity/column, but the resulting index is computed in row-major order. As an illustration:

(a + b + c) × (d + e + f) ≅ a × d + a × e + a × f + b × d + b × e + b × f + c × d + c × e + c × f

Examples:
> (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]
A variant-aware version of let*-values. Works with variants.

Examples:
> (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)

A variant-aware version of define-values. Works with variants.

Examples:
> (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