How can I tell Typed Racket that xexpressions are xexpressions?

16 views
Skip to first unread message

Marc Kaufmann

unread,
Dec 10, 2019, 1:44:59 PM12/10/19
to Racket Users
Welcome to this week's edition of "Confusing myself with Typed Racket".*

I want to import `response/xexpr-wrap` -- a version of `response/xexpr` that does some additional styling -- in a typed/racket file. So thanks to Ben and Jon in another thread, I now do

```
(require/typed xml [#:opaque Xexpr xexpr?])
(require/typed "tools.rkt" [#:opaque Response response?] [response/xexpr-wrap (-> Xexpr Response)])

(define x '(body (h1 "Not so Hello world")))
(response/xexpr-wrap x)
```

And this does not work. I get the error

```
expected: Xexpr
given: (List 'body (List 'h1 String))
```

even though it passes the `(xexpr? x)` passes, returning #t. I was somewhat surprised by this, but I guess the issue is that opaque types can only work at runtime on code from non-typed modules. However, since I pass `x` as an argument in my file, the type checker wants to type check it now, rather than putting contracts around the arguments passed into `response/xexpr-wrap`.

If this is the case, is it possible to use opaque types to type check arguments into functions required from non-typed modules? Well, I can probably hack my way around this: I write a non-typed function in `tools.rkt` called `this-is-an-xexpr` which I require/typed with `(-> Any Xexpr)`, which if I understand things correctly should put run-time contracts around that function, but type check. (See below, I went and checked whether this worked, and it does.) A less hacky way would be to be less lazy and define an Xexpr type via `define-type Xexpr (U String Symbol (Listof ...)...)` and so on. This is probably what I'll do, but I wanted to know what is going on anyway.

If it is not the case, what is going on that makes this not work?

Despite having found a way to make this work, I'd like to know if there is a non-hacky way, whether I understand correctly why my naive approach failed, and what the (or a) recommended way of doing this is.

Cheers - until next time.

Marc

EDIT LATER: Hah, my hack works!

```{tools.rkt}
#lang racket

(provide make-xexpr ...)
(define (make-xexpr xexpr)
  xexpr)
```

and then in my typed file:

```
#lang typed/racket

(require/typed "tools.rkt"
              [#:opaque Response response?]
              [#:opaque Xexpr xexpr?]
              [make-xexpr (-> Any Xexpr)]
              [response/wrap-xexpr (-> Xexpr Response)])

(define x '(body (h1 "Not so Hello world")))
(response/wrap-xexpr (make-xexpr x))
```

and this works. Nice, in an ugly kind of way.

*: Despite said confusion, ever since I got past the initial hump of using Typed Racket, it's been really useful though as it catches a substantial fraction of my bugs that would require sprinkling lots of printfairy dust to find and fix.
Reply all
Reply to author
Forward
0 new messages