WIP: Initial support for racket/contract in TR #417
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This pull request implements initial support for using racket/contract in TR.
Type system from a high-level
Contracts in TR have two type arguments and are written as
(Con S T)
.The first argument is the contract's input type, which specifies what it can
monitor. For example, using the function
positive?
as a contract would haveinput type Real. You can think of the input type like the function's domain.
The second argument is the contract's output type, which indicates extra
information we can conclude if the contract does not fail. For
positive?
, itsoutput type is
Positive-Real
. As you may have guessed, this information comesfrom the function type's propositions.
The entire contract type of
positive?
is(Con Real Positive-Real)
.A function contract like
(->/c positive? positive?)
has a slightly morecomplicated type. By the domain contract's output type, we know the function
contract will only allow
Positive-Real
s to get through to the function.Because the range contract can only monitor
Real
s, we know the function mustproduce a
Real
. Thus, we say that the input type of the function contract is(-> Positive-Real Real)
. We construct the output type of the function contractwith similar reasoning, and get that the entire type of the function contract is
(Con (-> Positive-Real Real) (-> Real Positive-Real))
.What's supported?
I mostly focused on the combinators found in the "Data Structure Contracts"
section of the docs, the function contract combinators
->
and->i
,provide/contract
, andcontract-out
.Notable missing forms:
->*
unsupplied-arg?
andthe-unsupplied-arg
from->i
struct/c
any
range contractBrief implementation details
Typed contract forms are provided by contract-prims.rkt (a name that is
annoyingly close to prims-contract.rkt). Most forms can be directly given a
type, e.g.
>/c
can be given a function type.Other combinator forms are a little more complicated. TR provides its own
version of these that annotate the surface syntax before delegating to the
racket/contract's version of the form. After expansion, TR recovers the
annotated pieces, typechecks those pieces, and uses that to calculate the type
of the contract.
One particularly tricky part of the implementatation is that contract-out and
provide/contract generate transformers for the provided, contracted, bindings.
We want typed code with contracts on it to be able to go to untyped code.
However, macros defined in TR are generally forbidden from doing so. These
bindings are special-cased in tc-toplevel. I don't know what implications this
has on TR's invariants.
Any sort of feedback is welcome---type system, implementation, comment prefix
syntax, etc. Yes, I'm missing user docs.