Skip to content

Commit 7595a2e

Browse files
authored
Generalise pairs to n-tuples (#19)
This (surprisingly annoying-to-write?) PR generalises the pairs that we had previously to tuples of arbitrary length. This will be useful for the multiple mailboxes extension. Note that currently we still can't do nested pattern matching: while we can construct `((1, 2), 3)`, we can't deconstruct it like `let ((x, y), z) = ((1, 2), 3) in y` just yet. One for another patch. This patch also removes the unit constant and unit type (which are nullary tuples and the nullary tuple type respectively). To preserve backwards compatibility, `Unit` is now an alias for `()`.
1 parent 8c0e688 commit 7595a2e

22 files changed

+334
-219
lines changed

lib/common/common_types.ml

-6
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,12 @@ module Base = struct
66
| Int
77
| Bool
88
| String
9-
| Unit
109
[@@deriving show]
1110

1211
let pp ppf =
1312
let ps = Format.pp_print_string ppf in
1413
function
1514
| Atom -> ps "Atom"
16-
| Unit -> ps "Unit"
1715
| Int -> ps "Int"
1816
| Bool -> ps "Bool"
1917
| String -> ps "String"
@@ -30,24 +28,20 @@ type tag = string
3028
(* Boxed constants *)
3129
module Constant = struct
3230
type t =
33-
| Unit
3431
| Int of int
3532
| String of string
3633
| Bool of bool
3734

3835
let type_of = function
39-
| Unit -> Base.Unit
4036
| Int _ -> Base.Int
4137
| Bool _ -> Base.Bool
4238
| String _ -> Base.String
4339

4440
let pp ppf = function
45-
| Unit -> Format.pp_print_string ppf "()"
4641
| Int i -> Format.pp_print_int ppf i
4742
| String s -> Format.fprintf ppf "\"%s\"" s
4843
| Bool b -> Format.pp_print_bool ppf b
4944

50-
let unit = Unit
5145
let wrap_int i = Int i
5246
let wrap_string s = String s
5347
let wrap_bool b = Bool b

lib/common/ir.ml

+12-12
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,11 @@ and comp_node =
8585
args: value list
8686
}
8787
| If of { test: value; then_expr: comp; else_expr: comp }
88-
| LetPair of {
88+
| LetTuple of {
8989
(* By annotating with inferred pretypes, we can always use a checking rule
9090
during inference, irrespective of whether both of the binders are used. *)
91-
binders: ( ((Binder.t[@name "binder"]) * (Pretype.t[@name "pretype"]) option) *
92-
((Binder.t[@name "binder"]) * (Pretype.t[@name "pretype"]) option));
93-
pair: value;
91+
binders: ((Binder.t[@name "binder"]) * (Pretype.t[@name "pretype"]) option) list;
92+
tuple: value;
9493
cont: comp
9594
}
9695
| Case of {
@@ -119,7 +118,7 @@ and value_node =
119118
| Constant of constant
120119
| Primitive of primitive_name
121120
| Variable of (Var.t[@name "var"]) * (Pretype.t[@name "pretype"]) option
122-
| Pair of value * value
121+
| Tuple of value list
123122
| Inl of value
124123
| Inr of value
125124
| Lam of {
@@ -231,11 +230,11 @@ and pp_comp ppf comp_with_pos =
231230
pp_value target
232231
pp_message message
233232
end
234-
| LetPair { binders = ((b1, _), (b2, _)); pair; cont } ->
235-
fprintf ppf "let (%a, %a) = @[<v>%a@] in@,%a"
236-
Binder.pp b1
237-
Binder.pp b2
238-
pp_value pair
233+
| LetTuple { binders = bs; tuple; cont } ->
234+
let bs = List.map fst bs in
235+
fprintf ppf "let %a = @[<v>%a@] in@,%a"
236+
(pp_print_comma_list Binder.pp) bs
237+
pp_value tuple
239238
pp_comp cont
240239
| Case { term; branch1; branch2 } ->
241240
fprintf ppf
@@ -259,8 +258,8 @@ and pp_value ppf v =
259258
| Primitive prim -> Format.pp_print_string ppf prim
260259
| Variable (var, _) -> Var.pp ppf var
261260
| Constant c -> Constant.pp ppf c
262-
| Pair (v1, v2) ->
263-
fprintf ppf "(%a, %a)" pp_value v1 pp_value v2
261+
| Tuple vs ->
262+
fprintf ppf "%a" (pp_print_comma_list pp_value) vs
264263
| Inl v -> fprintf ppf "inl(%a)" pp_value v
265264
| Inr v -> fprintf ppf "inr(%a)" pp_value v
266265
| Lam { linear; parameters; result_type; body } ->
@@ -284,6 +283,7 @@ and pp_guard ppf guard_with_pos =
284283
| Fail ->
285284
fprintf ppf "fail"
286285

286+
let unit = Tuple []
287287

288288
let is_receive_guard = function
289289
| Receive _ -> true

lib/common/lib_types.ml

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ let signatures =
2020
in
2121
int_ops @ int_rel_ops @ bool_rel_ops @
2222
[
23-
("print", function_type false [Base Base.String] (Base Base.Unit));
24-
("concat", function_type false [Base Base.String; Base Base.String] (Base Base.String));
23+
("print", function_type false [Base Base.String] Type.unit_type);
24+
("concat", function_type false [Base Base.String; Base Base.String] Type.string_type);
2525
("rand", function_type false [Base Base.Int] (Base Base.Int));
26-
("sleep", function_type false [Base Base.Int] (Base Base.Unit));
26+
("sleep", function_type false [Base Base.Int] Type.unit_type);
2727
("intToString", function_type false [Base Base.Int] (Base Base.String))
2828
]

lib/common/pretype.ml

+23-18
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,30 @@ type t =
1414
| PFun of { linear: bool; args: (Type.t[@name "ty"]) list; result: t[@name "pretype"] }
1515
| PInterface of string
1616
| PSum of (t * t)
17-
| PPair of (t * t)
17+
| PTuple of t list
1818
[@@name "pretype"]
1919
[@@deriving visitors { variety = "map" }]
2020
and base = [%import: Common_types.Base.t]
2121

22+
let unit = PTuple []
23+
2224
let rec pp ppf =
23-
let ps = Format.pp_print_string ppf in
25+
let open Format in
26+
let ps = pp_print_string ppf in
2427
function
2528
| PBase b -> Common_types.Base.pp ppf b
2629
| PFun { linear; args; result } ->
2730
let arrow = if linear then "-o" else "->" in
28-
Format.fprintf ppf "(%a) %s %a"
31+
fprintf ppf "(%a) %s %a"
2932
(pp_print_comma_list Type.pp) args
3033
arrow
3134
pp result
32-
| PPair (t1, t2) ->
33-
Format.fprintf ppf "(%a * %a)"
34-
pp t1
35-
pp t2
35+
| PTuple ts ->
36+
let pp_star ppf () = pp_print_string ppf " * " in
37+
fprintf ppf "(%a)"
38+
(pp_print_list ~pp_sep:(pp_star) pp) ts
3639
| PSum (t1, t2) ->
37-
Format.fprintf ppf "(%a + %a)"
40+
fprintf ppf "(%a + %a)"
3841
pp t1
3942
pp t2
4043
| PInterface name -> ps name
@@ -48,7 +51,7 @@ let rec of_type = function
4851
| Type.Base b -> PBase b
4952
| Type.Fun { linear; args; result } ->
5053
PFun { linear; args; result = of_type result }
51-
| Type.Pair (t1, t2) -> PPair (of_type t1, of_type t2)
54+
| Type.Tuple ts -> PTuple (List.map of_type ts)
5255
| Type.Sum (t1, t2) -> PSum (of_type t1, of_type t2)
5356
| Type.Mailbox { interface; _ } -> PInterface interface
5457

@@ -63,16 +66,18 @@ let rec to_type = function
6366
(fun result ->
6467
Some (Type.Fun { linear; args; result })
6568
)
66-
| PPair (t1, t2) ->
67-
begin
68-
match to_type t1, to_type t2 with
69-
| Some ty1, Some ty2 -> Some (Type.Pair (ty1, ty2))
70-
| _, _ -> None
71-
end
69+
| PTuple ts ->
70+
let rec go acc =
71+
function
72+
| [] -> Some (List.rev acc)
73+
| x :: xs ->
74+
Option.bind (to_type x) (fun t -> go (t :: acc) xs)
75+
in
76+
Option.bind (go [] ts) (fun ts -> Some (Type.Tuple ts))
7277
| PSum (t1, t2) ->
7378
begin
74-
match to_type t1, to_type t2 with
75-
| Some ty1, Some ty2 -> Some (Type.Sum (ty1, ty2))
76-
| _, _ -> None
79+
match to_type t1, to_type t2 with
80+
| Some ty1, Some ty2 -> Some (Type.Sum (ty1, ty2))
81+
| _, _ -> None
7782
end
7883
| PInterface _ -> None

lib/common/sugar_ast.ml

+15-15
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ and expr_node =
3131
args: expr list
3232
}
3333
| If of { test: expr; then_expr: expr; else_expr: expr }
34-
(* Pairs *)
35-
| Pair of (expr * expr)
36-
| LetPair of {
37-
binders: sugar_binder * sugar_binder;
38-
annot: ((Type.t[@name "ty"]) * (Type.t[@name "ty"])) option;
34+
(* Tuples *)
35+
| Tuple of expr list
36+
| LetTuple of {
37+
binders: sugar_binder list;
38+
annot: ((Type.t[@name "ty"]) list) option;
3939
term: expr;
4040
cont: expr
4141
}
@@ -224,18 +224,18 @@ and pp_expr ppf expr_with_pos =
224224
pp_expr e1
225225
pp_bnd_ann bnd2
226226
pp_expr e2
227-
| Pair (e1, e2) ->
228-
fprintf ppf "(%a, %a)" pp_expr e1 pp_expr e2
229-
| LetPair { binders = (b1, b2); annot = None; term; cont } ->
230-
fprintf ppf "let (%s, %s) = %a in %a"
231-
b1 b2
227+
| Tuple es ->
228+
fprintf ppf "(%a)" (pp_print_comma_list pp_expr) es
229+
| LetTuple { binders = bs; annot = None; term; cont } ->
230+
fprintf ppf "let (%a) = %a in %a"
231+
(pp_print_comma_list pp_print_string) bs
232232
pp_expr term
233233
pp_expr cont
234-
| LetPair { binders = (b1, b2); annot = Some (t1, t2); term; cont } ->
235-
fprintf ppf "let (%s, %s) : (%a * %a) = %a in %a"
236-
b1 b2
237-
Type.pp t1
238-
Type.pp t2
234+
| LetTuple { binders = bs; annot = Some ts; term; cont } ->
235+
assert (List.length bs = List.length ts);
236+
fprintf ppf "let (%a) : (%a) = %a in %a"
237+
(pp_print_comma_list pp_print_string) bs
238+
(pp_print_comma_list Type.pp) ts
239239
pp_expr term
240240
pp_expr cont
241241
| Guard { target; pattern; guards; _ } ->

lib/common/type.ml

+16-15
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ end
251251
type t =
252252
| Base of base
253253
| Fun of { linear: bool; args: t list; result: t }
254-
| Pair of (t * t)
254+
| Tuple of t list
255255
| Sum of (t * t)
256256
| Mailbox of {
257257
capability: (Capability.t [@name "capability"]);
@@ -286,14 +286,15 @@ let is_mailbox_type = function
286286

287287
let rec contains_mailbox_type = function
288288
| Mailbox _ -> true
289-
| Sum (t1, t2) | Pair (t1, t2) -> contains_mailbox_type t1 || contains_mailbox_type t2
289+
| Sum (t1, t2) -> contains_mailbox_type t1 || contains_mailbox_type t2
290+
| Tuple ts -> List.exists contains_mailbox_type ts
290291
| _ -> false
291292

292293
(* Easy constructors *)
293294
let int_type = Base Base.Int
294295
let string_type = Base Base.String
295296
let bool_type = Base Base.Bool
296-
let unit_type = Base Base.Unit
297+
let unit_type = Tuple []
297298
let atom = Base Base.Atom
298299
let function_type linear args result =
299300
Fun { linear; args; result }
@@ -316,10 +317,10 @@ let rec pp ppf =
316317
(pp_print_comma_list pp) args
317318
arrow
318319
pp result
319-
| Pair (t1, t2) ->
320-
fprintf ppf "(%a * %a)"
321-
pp t1
322-
pp t2
320+
| Tuple ts ->
321+
let pp_star ppf () = pp_print_string ppf " * " in
322+
fprintf ppf "(%a)"
323+
(pp_print_list ~pp_sep:(pp_star) pp) ts
323324
| Sum (t1, t2) ->
324325
fprintf ppf "(%a + %a)"
325326
pp t1
@@ -355,7 +356,7 @@ let rec is_lin = function
355356
| Fun { linear; _ } -> linear
356357
(* !1 is unrestricted... *)
357358
| Mailbox { capability = Out; pattern = Some One; _ } -> false
358-
| Pair (t1, t2) -> is_lin t1 || is_lin t2
359+
| Tuple ts -> List.exists is_lin ts
359360
| Sum (t1, t2) -> is_lin t1 || is_lin t2
360361
(* ...but otherwise a mailbox type must be used linearly. *)
361362
| Mailbox _ -> true
@@ -368,8 +369,8 @@ let is_output_mailbox = function
368369
| Mailbox { capability = Out; pattern = Some _; _ } -> true
369370
| _ -> false
370371

371-
let is_pair = function
372-
| Pair _ -> true
372+
let is_tuple = function
373+
| Tuple _ -> true
373374
| _ -> false
374375

375376
let is_sum = function
@@ -391,13 +392,13 @@ let get_quasilinearity = function
391392

392393
let rec make_usable = function
393394
| Mailbox m -> Mailbox { m with quasilinearity = Quasilinearity.Usable }
394-
| Pair (t1, t2) -> Pair (make_usable t1, make_usable t2)
395+
| Tuple ts -> Tuple (List.map make_usable ts)
395396
| Sum (t1, t2) -> Sum (make_usable t1, make_usable t2)
396397
| t -> t
397398

398399
let rec make_returnable = function
399400
| Mailbox m -> Mailbox { m with quasilinearity = Quasilinearity.Returnable }
400-
| Pair (t1, t2) -> Pair (make_returnable t1, make_returnable t2)
401+
| Tuple ts -> Tuple (List.map make_returnable ts)
401402
| Sum (t1, t2) -> Sum (make_returnable t1, make_returnable t2)
402403
| t -> t
403404

@@ -406,15 +407,15 @@ let is_unr = is_lin >> not
406407
let rec is_returnable = function
407408
| Mailbox { quasilinearity = ql; _ } ->
408409
ql = Quasilinearity.Returnable
409-
| Pair (t1, t2)
410+
| Tuple ts -> List.for_all is_returnable ts
410411
| Sum (t1, t2) -> is_returnable t1 && is_returnable t2
411412
| _ -> true
412413

413414
let make_function_type linear args result =
414415
Fun { linear; args; result }
415416

416-
let make_pair_type ty1 ty2 =
417-
Pair (make_returnable ty1, make_returnable ty2)
417+
let make_tuple_type tys =
418+
Tuple (List.map make_returnable tys)
418419

419420
let make_sum_type ty1 ty2 =
420421
Sum (make_returnable ty1, make_returnable ty2)

lib/frontend/desugar_let_annotations.ml

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ let visitor =
1717
let body = self#visit_expr env body in
1818
let term = { expr_with_pos with node = Annotate (inner_term, Type.make_returnable annot') } in
1919
{ expr_with_pos with node = Let { binder; annot = None; term; body } }
20-
| LetPair { binders; annot = Some (ty1, ty2); term; cont } ->
20+
| LetTuple { binders; annot = Some tys; term; cont } ->
2121
let cont = self#visit_expr env cont in
2222
let term =
2323
{ expr_with_pos with node =
24-
Annotate (term, Type.make_returnable (Type.make_pair_type ty1 ty2)) }
24+
Annotate (term, Type.make_returnable (Type.make_tuple_type tys)) }
2525
in
26-
{ expr_with_pos with node = LetPair { binders; annot = None; term; cont } }
26+
{ expr_with_pos with node = LetTuple { binders; annot = None; term; cont } }
2727
| _ -> super#visit_expr env expr_with_pos
2828
end
2929

lib/frontend/insert_pattern_variables.ml

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ let rec annotate_type =
1818
args = List.map annotate_type args;
1919
result = annotate_type result
2020
}
21-
| Pair (t1, t2) ->
22-
Pair (annotate_type t1, annotate_type t2)
21+
| Tuple ts ->
22+
Tuple (List.map annotate_type ts)
2323
| Sum (t1, t2) ->
2424
Sum (annotate_type t1, annotate_type t2)
2525
| Mailbox { pattern = Some _; _ } as mb -> mb

0 commit comments

Comments
 (0)