macrosracketplai

How to implement define-type and type-case in Racket using macros?


define-type and type-case are provided in plai scheme, but for some reason they are not present in typed/racket. I want to implement these constructs in racket using macros.

I want to create a macro "def-user-type" following is the syntax I want to use

    (def-user-type Shape
      [Rectangle ((l Number) (b Number))]
      [Circle    ((r radius))]
      [Blah      (())])

And it should roughly behave as following

    (define-type Shape (U Rectangle Circle Blah))
    (struct: Rectangle ([l : Number] [b Number]))
    (struct: Circle ([r : Number]))
    (struct: Blah ())

This is what I have achieved so far. It is incorrect and the error message given by racket compiler is not helping either.

#lang typed/racket
(define-syntax define-user-type
  (syntax-rules()
    [(define-user-type type-name
       [sub-type ((field-name type) ...)]
       ...)
     ((define-type type-name (U sub-type ...))
     (struct: sub-type ([field-name : type] ...))
     ...)]))

Please guide me. thanks!


Solution

  • You seem to be asking more than one question.

    First, Typed Racket has a define-type but it's probably a little different from the version in #lang plai. You can see the implementations of plai's define-type and type-case here.

    Second, there are a couple of problems with your macro.

    1. The right-hand side of your syntax-rules clause is applying the result of define-type as a function, which won't work. Try using a begin to combine the expressions.

    2. Your use of your def-user-type macro is not following the definition. The definition requires zero or more (field-name type) pairs, but in Blah you give (), which is not a pair.

    3. radius is an undefined type

    Here is a version of your macro with the suggested changes:

    #lang typed/racket
    
    (define-syntax def-user-type
      (syntax-rules ()
        [(_ type-name [sub-type ((field-name type) ...)] ...)
         (begin
           (define-type type-name (U sub-type ...))
           (struct: sub-type ([field-name : type] ...)) ...)]))
    
    (def-user-type Shape
      [Rectangle ((l Number) (b Number))]
      [Circle    ((r Number))]
      [Blah      ()])
    

    And here is an example that uses a Rectangle as a Shape:

    > ((λ: ([x : Shape]) x) (Rectangle 1 2))
    - : Shape
    #<Rectangle>