bidirectional-type-checking/bidi.ml
2021-02-11 03:41:12 -06:00

40 lines
1.1 KiB
OCaml

type expr =
| EUnit (* () *)
| EVar of string (* x *)
| EAbs of string * expr (* λx.e *)
| EApp of expr * expr (* e.e *)
| EAnnot of expr * ty (* e:A *)
and ty =
| TUnit (* () *)
| TFun of ty * ty (* A->A *)
type err =
| UnboundName of string
| CantApplyNonFunc
| NeedsAnnotation of string
type ctx = (string * ty) list
let rec infer (ctx: ctx) (expr: expr): (ty, err) result =
match expr with
| EUnit -> Ok TUnit
| EVar name ->
List.find_opt (fun (n, _) -> n = name) ctx
|> Option.to_result ~none:(UnboundName name)
|> Result.map snd
| EAnnot (_, ty) -> Ok ty
| EApp (func, arg) ->
begin match infer ctx func with
| Ok (TFun (a, b)) -> check ctx arg a |> Result.map (Fun.const b)
| Ok _ -> Error CantApplyNonFunc
| Error e -> Error e
end
| EAbs (name, _) -> Error (NeedsAnnotation name)
and check (ctx: ctx) (expr: expr) (ty: ty): (unit, err) result =
match (expr, ty) with
| (EAbs (name, body), TFun (argt, bodyt)) -> check ((name, argt) :: ctx) body bodyt
| _ -> infer ctx expr |> Result.map (Fun.const ())
(* vim: set sw=2 : *)