Module Smyth.Type

Helpers

val equal : Lang.typ -> Lang.typ -> bool

equal tau1 tau2 determines if tau1 and tau2 have the same abstract syntax tree.

val wildcard : Lang.typ

The "wildcard" type.

val matches : Lang.typ -> Lang.typ -> bool

matches tau1 tau2 determines if tau1 and tau2 have the same abstract syntax tree modulo any wildcards.

val is_base : Lang.typ -> bool

is_base tau returns determines if tau is a base type.

val domain_of_codomain : codomain:Lang.typ -> Lang.typ -> Lang.typ option

domain_of_codomain ~codomain root looks for codomain on the right-hand side of a type arrow in root that is not on the left-hand side of any type arrow and, if found, returns the left-hand side of that type arrow.

For example, suppose tau = a -> (b -> (c -> d)). Then:

domain_of_codomain ~codomain:d tau = Some c
domain_of_codomain ~codomain:(c -> d) tau = Some b
domain_of_codomain ~codomain:(b -> (c -> d)) tau = Some a
domain_of_codomain ~codomain:(a -> (b -> (c -> d))) tau = None

Also:

domain_of_codomain ~codomain:a a = None
domain_of_codomain ~codomain:a (() -> a) = Some ()
val bind_spec : Lang.type_ctx -> Lang.exp -> Lang.bind_spec

bind_spec gamma e returns the computed binding specification of e with respect to gamma. In particular:

  • Projections decrease the binding specification of their argument
  • Variables are looked up in gamma
val sub_bind_spec : Lang.bind_spec -> Lang.bind_spec

sub_bind_spec b "decreases" the binding specification b. In particular, if b is a binding specification for the argument of some function, then sub_bind_spec b will be a binding specification for decreasing on that function.

val structurally_decreasing_bind_spec : head_spec:Lang.bind_spec -> arg_spec:Lang.bind_spec -> bool

structurally_decreasing_bind_spec ~head_spec ~arg_spec determines if arg_spec is decreasing on head_spec. If head_spec is not a binding specification for a recursive function, then structurally_decreasing ~head_spec ~arg_spec will return true.

val structurally_decreasing : Lang.type_ctx -> head:Lang.exp -> arg:Lang.exp -> bool

structurally_decreasing gamma ~head ~arg determines if arg is structurally decreasing on head in the context gamma.

val matches_dec : string option -> Lang.bind_spec -> bool

matches_dec (Some f) bind_spec determines if bind_spec is structurally decreasing on the recursive function f. matches_dec None bind_spec will always return true.

val peel_forall : Lang.typ -> string list * Lang.typ

Peels all outer universal quantifiers on a type into a list. For example:

peel_forall (forall a . forall b . a * b) = (["a", "b"], a * b)
peel_forall a = ([], a)
peel_forall (int * int) = ([], int * int)
peel_forall (forall c . int) = (["c"], int)
peel_forall (forall c . d) = (["c"], d)

Substitution

val substitute : before:string -> after:Lang.typ -> Lang.typ -> Lang.typ

substitute ~before ~after tau substitutes replaces free occurrences of before in tau with after.

val substitute_many : bindings:(string * Lang.typ) list -> Lang.typ -> Lang.typ

Performs many substitutions one after another; see substitute.

Type-checking

The following functions implement a bidirectional type checker.

type error =
| VarNotFound of string
| CtorNotFound of string
| PatternMatchFailure of Lang.typ * Lang.pat
| WrongNumberOfTypeArguments of int * int
| GotFunctionButExpected of Lang.typ
| GotTupleButExpected of Lang.typ
| GotTypeAbstractionButExpected of Lang.typ
| GotButExpected of Lang.typ * Lang.typ
| BranchMismatch of string * string
| CannotInferFunctionType
| CannotInferCaseType
| CannotInferHoleType
| ExpectedArrowButGot of Lang.typ
| ExpectedTupleButGot of Lang.typ
| ExpectedForallButGot of Lang.typ
| ExpectedDatatypeButGot of Lang.typ
| TupleLengthMismatch of Lang.typ
| ProjectionLengthMismatch of Lang.typ
| ProjectionOutOfBounds of int * int
| TypeAbstractionParameterNameMismatch of string * string
| AssertionTypeMismatch of Lang.typ * Lang.typ

Type-checking errors.

val check : Lang.datatype_ctx -> Lang.type_ctx -> Lang.exp -> Lang.typ -> (Lang.hole_ctxLang.exp * error) Stdlib.result

Bidirectional type "checking".

val infer : Lang.datatype_ctx -> Lang.type_ctx -> Lang.exp -> (Lang.typ * Lang.hole_ctxLang.exp * error) Stdlib.result

Bidirectional type "inference" or "synthesis".