lexi-lambda/hackett

Racket/Hackett FFI + contract generation

Opened this issue · 0 comments

Like Typed Racket, Hackett should support safe interop with Racket, with boundaries protected with contracts. The interoperation story is more complicated with Hackett because it’s semantically more distant from Racket than Typed Racket is. For example:

  • Hackett is a lazy language, so values need to be forced when crossing from Hackett to Racket. In fact, they need to be recursively forced, so values that cross the boundary probably need to, at a bare minimum, implement a deepseq-style NFData typeclass.

  • Hackett functions are curried, which are unpleasant and unidiomatic to use from Racket.

  • Hackett has typeclasses, and typeclass resolution often can’t be done based on runtime values (for example, it can be based on the return type or even a phantom type with no runtime evidence), so it’s probably not possible to call typeclass-constrained functions from Racket.

  • Hackett is pure, so Racket code could potentially break invariants that Hackett code assumes. This is probably unavoidable, though, and Hackett users can technically use unsafe-run-io! themselves if they want, anyway.

It would be possible to create To-Racket and From-Racket typeclasses, or something like that, which have type signatures that include an entirely opaque Racket datatype, with some built-in instances for primitive datatypes. This way, conversions could only be defined in terms of the built-in conversions, and the typeclasses could be used to guide contract generation. The obvious downside of this is that crossing a boundary would be enormously expensive, so maybe there’s a way to do something similar using a typed representation of contracts (type-indexed contracts?) that would be more efficient.