def desugar_equation(self, params, param_types, result_type, equation): position = equation.position patterns = equation.lhs.application_args() body = equation.rhs if len(patterns) != len(params): self.fail('equations-arity-mismatch', name=name, position=position) self._env.open_scope() # Equation scope fvs = set() for var in syntax.free_variables_list(patterns): if not self._env.is_defined(var): fvs.add(var) self._env.define(var, syntax.Metavar(prefix="t", position=position)) # TODO: allow forced binding by prefixing a variable with "." if len(equation.where) == 0: d_type, d_body = self.check_expr(body) else: d_type, d_body = self.check_let( syntax.Let(declarations=equation.where, body=body, position=position)) self.unify_types(d_type, result_type) unif_goals = [] for param, pattern, t_param in zip(params, patterns, param_types): t_pattern, e_pattern = self.check_expr(pattern) self.unify_types(t_param, t_pattern) unif_goals.append(syntax.unify(param, e_pattern)) alternative = syntax.fresh_many( fvs, syntax.sequence_many1(unif_goals, d_body)) self._env.close_scope() # Equation scope return alternative
def unify(self, goals): if not goals: yield values.unit() return (value1, value2) = goals[0] goals = goals[1:] if not value1.is_decided(): for v1 in self.eval_value(value1): yield from self.unify([(v1, value2)] + goals) return elif not value2.is_decided(): for v2 in self.eval_value(value2): yield from self.unify([(value1, v2)] + goals) return if value1.is_integer_constant() and value2.is_integer_constant(): if value1.value == value2.value: yield from self.unify(goals) elif value1.is_rigid_structure() and value2.is_rigid_structure(): if value1.constructor == value2.constructor and \ len(value1.args) == len(value2.args): subgoals = list(zip(value1.args, value2.args)) yield from self.unify(subgoals + goals) # Same head: # x t1 ... tn == x s1 ... sn #elif val1.is_flex_structure() \ # and val2.is_flex_structure() \ # and val1.symbol == val2.symbol \ # and len(val1.args) == len(val2.args): # subgoals = list(zip(val1.args, val2.args)) # yield from self.unify(subgoals + goals) elif value1.is_flex_structure() and len(value1.args) == 0: # TODO: occurs check assert not value1.symbol.is_instantiated() # decided value1.symbol.instantiate(value2) yield from self.unify(goals) value1.symbol.uninstantiate() elif value1.is_flex_structure() and len(value1.args) > 0: # TODO: occurs check assert not value1.symbol.is_instantiated() # decided new_var = syntax.fresh_variable() params = [syntax.fresh_variable() for arg in value1.args] term = syntax.lambda_many( [p.name for p in params], syntax.alternative( syntax.sequence_many1( [ syntax.unify(p, a) for p, a in zip(params, value1.args) ], value2 # body ), syntax.application_many(new_var, params))) env = environment.PersistentEnvironment() env.define(new_var.name, values.FlexStructure(values.Metavar(prefix='F'), [])) value1.symbol.instantiate(values.Thunk(term, env)) yield from self.unify(goals) value1.symbol.uninstantiate() elif value2.is_flex_structure(): yield from self.unify([(value2, value1)] + goals) else: return # Otherwise we fail
def unify(self, goals): if len(goals) == 0: yield values.unit() return (val1, val2) = goals[0] goals = goals[1:] if not val1.is_decided(): for v1 in self.eval_value(val1): yield from self.unify([(v1, val2)] + goals) return elif not val2.is_decided(): for v2 in self.eval_value(val2): yield from self.unify([(val1, v2)] + goals) return if val1.is_integer_constant() and val2.is_integer_constant(): if val1.value == val2.value: yield from self.unify(goals) elif val1.is_rigid_structure() and val2.is_rigid_structure(): if val1.constructor == val2.constructor and \ len(val1.args) == len(val2.args): subgoals = list(zip(val1.args, val2.args)) yield from self.unify(subgoals + goals) # Same head: # x t1 ... tn == x s1 ... sn elif val1.is_flex_structure() \ and val2.is_flex_structure() \ and val1.symbol == val2.symbol \ and len(val1.args) == len(val2.args): subgoals = list(zip(val1.args, val2.args)) yield from self.unify(subgoals + goals) elif val1.is_flex_structure() and len(val1.args) == 0: # TODO: occurs check assert not val1.symbol.is_instantiated() # decided val1.symbol.instantiate(val2) yield from self.unify(goals) val1.symbol.uninstantiate() elif val1.is_flex_structure() and len(val1.args) > 0: # TODO: occurs check assert not val1.symbol.is_instantiated() # decided new_var = syntax.fresh_variable() params = [] u_goals = [] for arg in val1.args: param = syntax.fresh_variable() params.append(param) u_goals.append(syntax.unify(param, arg)) term = syntax.lambda_many( [p.name for p in params], syntax.alternative( syntax.sequence_many1( u_goals, val2 # body ), syntax.application_many(new_var, params))) env = environment.PersistentEnvironment() env.define(new_var.name, values.FlexStructure(values.Metavar(prefix='F'), [])) val1.symbol.instantiate(values.Thunk(term, env)) yield from self.unify(goals) val1.symbol.uninstantiate() elif val2.is_flex_structure(): yield from self.unify([(val2, val1)] + goals) elif val1.is_closure(): #print('OPEN') #print(val1.var) #print(val1.body) #print(val1.env) uvar = values.UniversalVariable(prefix=val1.var) uval = values.UniversalStructure(uvar, []) env1 = val1.env.extended() env2 = environment.PersistentEnvironment() env1.define(val1.var, uval) env2.define(val1.var, uval) lhs = values.Thunk(val1.body, env1) rhs = values.Thunk(syntax.Application(fun=val2, arg=uval), env2) for x in self.unify([(lhs, rhs)]): # TODO: # forbid metavariables pointing directly # or indirectly to uvar # (???) yield from self.unify(goals) elif val2.is_closure(): yield from self.unify([(val2, val1)] + goals) else: print(val1, val2) return # Otherwise we fail