3

I'm trying to imitate recursive types in OCaml in untyped Racket, but I can't seem to find documentation on defining recursive structs. How would I go about mapping this:

type example =
| Red
| Blue of example
| Yellow of example * example;;

into something in Racket?

I've tried the following:

(struct Red ())
(struct Blue (e1))
(struct Yellow (e1 e2))
(struct example/c
    (or/c (Red)
          (Blue example/c)
          (Yellow example/c example/c)))

However, it doesn't work as expected when I put example/c in a contract, because it claims it's a procedure. Any help?

podington
  • 179
  • 1
  • 8

1 Answers1

4

I have changed the example. Here is an example where the variable e has the contract example/c.

#lang racket

(struct Red     ()      #:transparent)
(struct Blue    (e1)    #:transparent)
(struct Yellow  (e1 e2) #:transparent)

(define example/c
  (flat-murec-contract ([red/c     (struct/c Red)]
                        [blue/c    (struct/c Blue   example/c)]
                        [yellow/c  (struct/c Yellow example/c example/c)]
                        [example/c (or/c red/c blue/c yellow/c)])
                       example/c))


(define r (Red))
(define b (Blue r))
(define y (Yellow r b))
(define e y)

(provide (contract-out [e example/c]))

(match e
  [(Red)          (list "Red")]
  [(Blue   e1)    (list "Blue" e1)]
  [(Yellow e1 e2) (list "Yellow" e1 e2)]
  [else           "huh"])

If you change, say, (Yellow r b) to (Yellow r 42) then you get an error.

soegaard
  • 30,661
  • 4
  • 57
  • 106
  • Kind of? My end goal is to write a function and its contract that takes in an example struct and recursively translates it to a string. So, for instance, the contract would look something like: `[myfunc (example/c . -> . string?)]`. – podington Oct 09 '16 at 05:55
  • I think the edit works. Thanks! I'm a little confused on the bottom portion (after the definition of example/c), however. What is this trying to do? Also, it seems like it's being define such that Blue can only take in Red structs, although it should be able to take Yellow or another Blue as well, right? – podington Oct 09 '16 at 16:19
  • The part after the definition of `example/c` is an example. The variable `r` is bound to a `Red` struct. The variable `b` is bound to a `Blue` struct. The variable `y` is bound to a `Yellow` struct. Finally `e` must be either a Red, Blue, or, Yellow struct. Here it is the Yellow struct. Finally the variable `e` is exported. If you change, say, `(define y (Yellow r b))` to `(define y (Yellow r 42))` then `y` is not a legal `yellow/c` since 42 is not an `example/c`. Therefore the contract for `e` will indicate that `e` is not a legal `example/c`. – soegaard Oct 09 '16 at 16:21
  • Ah, that makes more sense. I thought it was something completely new for a second. As a followup, how would I properly match an object of type `example/c`? When pattern matching with an incorrect argument (one not of type `example/c`), I get a "match: no matching for clause {arg}" instead of a contract exception. Any suggestions? – podington Oct 09 '16 at 17:56
  • I have added an expression that shows how to use match. – soegaard Oct 09 '16 at 18:21
  • Mhmm, that's what I have currently, but instead of resorting to `else "huh"`, is there an implicit way to throw a contract exception saying the input was not a valid `example/c`? – podington Oct 09 '16 at 19:13
  • Use `raise-contract-error` see http://docs.racket-lang.org/reference/Legacy_Contracts.html?q=raise-#%28def._%28%28lib._racket%2Fcontract..rkt%29._raise-contract-error%29%29 – soegaard Oct 09 '16 at 19:14
  • Or ... if the match expression is in the body of a function, put a contract on the function - that way you can be sure that the value that reaches `match` always is an example/c. – soegaard Oct 09 '16 at 19:15