-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace Symbols.t
by Var.t
in binders and substitutions
#976
Conversation
f595c29
to
b406d45
Compare
let underscore = | ||
Random.self_init (); | ||
of_string @@ Format.sprintf "_%d" (Random.int 1_000_000) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, I was not aware we were doing that — this does not seem safe at all! We should use a counter instead (there are no guarantees that two consecutive Random.int
calls won't return the same value, which would be problematic as forall x, y : int. x + y
would become forall _1, _1: int. _1 + _1
which… is not the same at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Opened #977
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah ah :) you don't know the best part of our mighty codebase I see :)
This snippet is pure gold. I shared it one year ago on zulip, best joke of my short software developer career.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! But what I said above is not true — underscore is a global variable, not a function. OK, that makes things better — there can "just" be conflicts with a variable named _n
for some n
that changes each time Alt-Ergo is run. We should just call this "._"
instead, no?
@@ -116,12 +116,13 @@ let rec make_term up_qv quant_basename t = | |||
|
|||
| TTlet (binders, t2) -> | |||
let binders = | |||
List.rev_map (fun (s, t1) -> s, mk_term t1) | |||
List.rev_map (fun (s, t1) -> | |||
match s with Sy.Var v -> v, mk_term t1 | _ -> assert false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this invariant really always true? In that case, could we replace the type of binders by a list of Var.t
s?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I'm checking it right now. I forgot to do it before publishing the PR. I hope the legacy parser enforce this invariant (the new one does).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, before submitting this PR, I tried to change the type of the binders in the legacy typechecker. This will requires to change many types, mostly because the typechecker aggregates the symbols in a context, so embed variables into symbols makes the design simpler here. I decided to keep the code as before. The only place where we produce a new TTlet
term is here:
alt-ergo/src/lib/frontend/typechecker.ml
Lines 913 to 934 in 7363cd0
| PPlet(l, t2) -> | |
let _ = | |
List.fold_left (fun z (sy,_) -> | |
if Util.SS.mem sy z then | |
Errors.typing_error (DuplicatePattern sy) loc; | |
Util.SS.add sy z | |
)Util.SS.empty l | |
in | |
let rev_l = List.rev_map (fun (sy, t) -> sy, type_term env t) l in | |
let env = | |
List.fold_left | |
(fun env (sy, te1) -> | |
let ty1 = Ty.shorten te1.c.tt_ty in | |
let fvar s = Symbols.var @@ Var.of_string s in | |
Env.add env [sy] fvar ty1 | |
)env rev_l | |
in | |
let te2 = type_term env t2 in | |
let ty2 = Ty.shorten te2.c.tt_ty in | |
let l = List.rev_map (fun (sy, t) -> fst (Env.find env sy), t) rev_l in | |
Options.tool_req 1 (append_type "TR-Typing-Let type" ty2); | |
TTlet(l, te2), ty2 |
As you can see line 926, we store new variables in the environment of the typechecker and we retrieve them at the line 932 to produce the list of binders. Thus, the binders are always variables (embedded in symbols).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest you add to the assert false a TODO stating that we could actually simplify but it would require to update some legacy code which was out of the scope of the PR adding this assert false (and a reference to typechecker.ml).
src/lib/structures/expr.ml
Outdated
let fresh_sy = Sy.fresh_skolem ~is_var:true "Pur-Ite" in | ||
mk_term fresh_sy [] t.ty , add_let fresh_sy t lets | ||
let fresh_var = | ||
match Sy.fresh_skolem ~is_var:true "Pur-Ite" with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is better to add a Symbols.fresh_skolem_name
instead of creating a var and destroying it with an assert false
(or simple export the SkolemId from symbols)? I wonder if the current fresh_skolem
function is still relevant: is there still cases in your PR where fresh_skolem
is called with without creating a var
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll check. Good catch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function Symbols.fresh_skolem
isn't necessary anymore. I create a two functions fresh_skolem_string
and fresh_skolem_name
. It would be better to extract the module of identifiers from the Symbols
module and create a function fresk_skolem
in Var
but it's a small detail.
af95041
to
ec4d4d2
Compare
@@ -116,12 +116,13 @@ let rec make_term up_qv quant_basename t = | |||
|
|||
| TTlet (binders, t2) -> | |||
let binders = | |||
List.rev_map (fun (s, t1) -> s, mk_term t1) | |||
List.rev_map (fun (s, t1) -> | |||
match s with Sy.Var v -> v, mk_term t1 | _ -> assert false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest you add to the assert false a TODO stating that we could actually simplify but it would require to update some legacy code which was out of the scope of the PR adding this assert false (and a reference to typechecker.ml).
a9f4dce
to
dda574b
Compare
Alt-Ergo embeds variables into symbols then expressions. It's a good design but at many places in the codebase, we use symboles where variables are clearly sufficient. For instance, we shouldn't use symbols in substitutions or binders because we always bind a variable to an expression or substitute a variable by an expression. Let's use the simpler type `Var.t` as much as possible. This commit should be safe because the comparison functions of `Symbols.t` and `Var.t` agree on variables.
We need to create fresh variables without embed them in symbols as we now store binders in variable maps.
Alt-Ergo embeds variables into symbols then expressions. It's a good design but at many places in the codebase, we use symboles where variables are clearly sufficient.
For instance, we shouldn't use symbols in substitutions or binders because we always bind a variable to an expression or substitute a variable by an expression.
Let's use the simpler type
Var.t
as much as possible.This commit should be safe because the comparison functions of
Symbols.t
andVar.t
agree on variables.