|
| 1 | +(** |
| 2 | +
|
| 3 | + This module defines constraint language. |
| 4 | +
|
| 5 | + The constraint language has applicative structure (see [C_map] constructor) |
| 6 | + which is used for elaboration (the constraint solving algo computes a value). |
| 7 | +
|
| 8 | + *) |
| 9 | + |
| 10 | +open Base |
| 11 | +open Syntax |
| 12 | + |
| 13 | +type _ t = |
| 14 | + | C_trivial : unit t |
| 15 | + (** A trivial constraint, states nothing useful. Always can be solved. *) |
| 16 | + | C_eq : ty * ty -> unit t |
| 17 | + (** [C_eq (ty1, ty2)] states that the types [ty1] and [ty2] are equal. *) |
| 18 | + | C_inst : name * ty -> expr t |
| 19 | + (** [C_inst (name, ty)] states that [name] should be fetched from the |
| 20 | + environment, instantiated and equated to [ty]. *) |
| 21 | + | C_and : 'a t * 'b t -> ('a * 'b) t |
| 22 | + (** Conjuction of two constraints, possibly of different value type. *) |
| 23 | + | C_and_list : 'a t list -> 'a list t |
| 24 | + (** Conjuction of multiple constraints of the same value type. *) |
| 25 | + | C_exists : var list * 'a t -> 'a t |
| 26 | + (** [C_exists (vs, c)] existentially quantifies variables [vs] over [c]. *) |
| 27 | + | C_let : |
| 28 | + (name * var list * expr t * ty) list * 'b t |
| 29 | + -> ((expr * ty_sch) list * 'b) t |
| 30 | + (** [C_let (bindings, c)] works is a constraint abstraction fused with |
| 31 | + existential quantification. It adds [bindings] to the environment of |
| 32 | + the following constraint [c]. |
| 33 | +
|
| 34 | + It allows to define multiple names at once to support n-ary functions. *) |
| 35 | + | C_map : 'a t * ('a -> 'b) -> 'b t |
| 36 | + (** Map operation, this gives an applicative structure. *) |
| 37 | + |
| 38 | +let trivial = C_trivial |
| 39 | + |
| 40 | +let return v = C_map (C_trivial, fun () -> v) |
| 41 | + |
| 42 | +let ( =~ ) x y = C_eq (x, y) |
| 43 | + |
| 44 | +let inst name cty = C_inst (name, cty) |
| 45 | + |
| 46 | +let exists tys c = |
| 47 | + match tys with |
| 48 | + | [] -> c |
| 49 | + | tys -> ( |
| 50 | + match c with |
| 51 | + | C_exists (tys', c) -> C_exists (tys @ tys', c) |
| 52 | + | c -> C_exists (tys, c)) |
| 53 | + |
| 54 | +let let_in bindings c = C_let (bindings, c) |
| 55 | + |
| 56 | +let ( &~ ) x y = C_and (x, y) |
| 57 | + |
| 58 | +let ( >>| ) c f = C_map (c, f) |
| 59 | + |
| 60 | +let list cs = C_and_list cs |
| 61 | + |
| 62 | +let rec layout' : type a. names:Names.t -> a t -> PPrint.document = |
| 63 | + fun ~names c -> |
| 64 | + let open PPrint in |
| 65 | + match c with |
| 66 | + | C_trivial -> string "TRUE" |
| 67 | + | C_eq (ty1, ty2) -> |
| 68 | + layout_ty' ~names ty1 ^^ string " = " ^^ layout_ty' ~names ty2 |
| 69 | + | C_and (a, b) -> layout' ~names a ^^ string " & " ^^ layout' ~names b |
| 70 | + | C_and_list cs -> |
| 71 | + let sep = string " & " in |
| 72 | + separate sep (List.map cs ~f:(layout' ~names)) |
| 73 | + | C_exists (vs, c) -> |
| 74 | + string "∃" |
| 75 | + ^^ separate comma (List.map vs ~f:(layout_con_var' ~names)) |
| 76 | + ^^ dot |
| 77 | + ^^ parens (layout' ~names c) |
| 78 | + | C_let (bindings, c) -> |
| 79 | + let layout_cty' : type a. a t * ty -> document = function |
| 80 | + | C_trivial, ty -> layout_ty' ~names ty |
| 81 | + | c, ty -> layout' ~names c ^^ string " => " ^^ layout_ty' ~names ty |
| 82 | + in |
| 83 | + let layout_binding : type a. string * var list * a t * ty -> document = |
| 84 | + fun (name, vs, c, ty) -> |
| 85 | + string name |
| 86 | + ^^ string " : " |
| 87 | + ^^ |
| 88 | + match vs with |
| 89 | + | [] -> layout_cty' (c, ty) |
| 90 | + | vs -> |
| 91 | + let vs = layout_var_prenex' ~names vs in |
| 92 | + vs ^^ layout_cty' (c, ty) |
| 93 | + in |
| 94 | + let sep = comma ^^ blank 1 in |
| 95 | + string "let " |
| 96 | + ^^ separate sep (List.map bindings ~f:layout_binding) |
| 97 | + ^^ string " in " |
| 98 | + ^^ layout' ~names c |
| 99 | + | C_inst (name, ty) -> string name ^^ string " ≲ " ^^ layout_ty' ~names ty |
| 100 | + | C_map (c, _f) -> layout' ~names c |
| 101 | + |
| 102 | +include ( |
| 103 | + struct |
| 104 | + type pack = P : _ t -> pack |
| 105 | + |
| 106 | + include Showable (struct |
| 107 | + type t = pack |
| 108 | + |
| 109 | + let layout (P c) = |
| 110 | + let names = Names.make () in |
| 111 | + layout' ~names c |
| 112 | + end) |
| 113 | + |
| 114 | + let layout c = layout (P c) |
| 115 | + |
| 116 | + let show c = show (P c) |
| 117 | + |
| 118 | + let print ?label c = print ?label (P c) |
| 119 | + end : |
| 120 | + sig |
| 121 | + val layout : _ t -> PPrint.document |
| 122 | + |
| 123 | + val show : _ t -> string |
| 124 | + |
| 125 | + val print : ?label:string -> _ t -> unit |
| 126 | + end) |
0 commit comments