[racket] proposal for variant types

From: Eric Tanter (etanter at dcc.uchile.cl)
Date: Mon Jun 10 16:41:53 EDT 2013


Sorry if this has been discussed before. 

One of the things I often miss while programming in Racket, is variant types. In Shriram's PLAI, there is a `define-type' form:

   (define-type Expr
     [num (n number?)]

This is very helpful, with two caveats:

1- it requires contracts on fields -- while this is a feature, it also departs from simple structs in Racket.

2- its syntax for variants corresponds to the `type-case' matching form, eg:

   (type-case Expr e
     [num (n) ...]

Note the `[num (n) ...]', while the constructor is `(num n)'.

After reading the nice thread on writing style, I came up with a very simple `define-type' form that has the advantage of addressing both issues above:

(define-type expr
 (num n)
 (add l r)
 (sub l r))

1- no contracts, just like standard structs

2- the syntax of a variant declaration, eg. `(num n)' directly corresponds to the constructor syntax, which is used in `match':

(define (interp expr)
  (match expr
    [(num n) n]

A first version of the macro, included at the end of this mail, makes all structs transparent by default (this could be changed of course):

> (num 10)
(num 10)
> (expr? (num 10))

and avoids the instantiation of the abstract type:

> (expr)
. . cannot construct value of type expr: use one of the variants (num add sub) 

I would actually love to have this facility in Racket, but I suspect that the fact that it is not there already (even though these variant types are common in other FP languages) is due to some "good reason" to not include it. 
If so, I'd like to understand why. 

And if there is interest and it is indeed possible to include it in Racket, I'd be happy to contribute it (after some polishing, of course).


-- Éric

(define-syntax-rule (define-type t (variant vfield ...) ...)
    (struct t ()
            (λ (const)
              (if (eq? const 't) 
                  (error (format "cannot construct value of type ~a: use one of the variants ~a"
                                 't (list 'variant ...)))
    (struct variant t (vfield ...) #:transparent) ...))

Posted on the users mailing list.