def print_app(expr): """Takes an application and prints it in the following manner: if the application is of the form (..(f a0)... an), print f(a0,...,an), or (a0 f a1) if f is infix. Arguments: - `expr`: an expression """ if conf.implicit: root, args = root_app_implicit(expr) if root.is_const() and root.info.print_iterable_app: return print_iterable_app(expr, root) elif root.is_const() and root.info.print_implies: return print_implies(expr) elif root.info.infix and len(args) == 2: return "({0!s} {1!s} {2!s})".format(args[0], root, args[1]) else: args_str = map(str, args) args_str = ", ".join(args_str) return "{0!s}({1!s})".format(root, args_str) else: root, args = root_app(expr) args_str = map(str, args) args_str = ", ".join(args_str) return "{0!s}({1!s})".format(root, args_str)
def __init__(self, inst): """ Arguments: - `inst`: the name of an instance declaration """ Tactic.__init__(self, 'instance {0!s}'\ .format(inst)) self.inst = inst self.root = e.root_app(e.root_clause(inst))[0]
def solve(self, goals, context): if len(goals) == 0: return [] else: prop = goals[0].prop root, _ = e.root_app(prop) if root.info.is_class and self.root.equals(root): return fast_apply(self.inst).solve(goals, context) else: mess = "Expression {0!s} is not an instance of {1!s}"\ .format(root, self.root) raise TacticFailure(mess, self, goals)
def visit_app(self, expr, model, bindings): #evaluate all the arguments at once. #Include the implicit arguments. f, args = e.root_app(expr) f_val = self.visit(f, model, bindings) args_val = [self.visit(a, model, bindings) for a in args] if (f_val is None): if self.strict: raise NoValue(expr) else: return None else: #call f "strictly" on the arguments #this is better performance-wise, but bad for #lazy evaluation return f_val(*args_val)
def definstance(name, ty, expr): """ Arguments: - `name`: a string - `ty`: a type of the form ClassName(t1,...,tn) """ root, _ = root_app(root_clause(ty)) if root.info.is_class: class_name = root.name c = defexpr(name, expr, type=ty, unfold=[class_name]) conf.current_ctxt().class_instances[name] = c.type conf.current_ctxt().hyps[name] = c.type return c else: raise Exception("Error in definition of {0!s}:"\ "expected {1!s} to be a class name"\ .format(name, root))
def definstance(name, ty, expr): """ Arguments: - `name`: a string - `ty`: a type of the form ClassName(t1,...,tn) """ root, _ = root_app(root_clause(ty)) if root.info.is_class: class_name = root.name c = defexpr(name, expr, type=ty, unfold=[class_name]) current_ctxt().class_instances[name] = c.type current_ctxt().hyps[name] = c.type return c else: raise Exception("Error in definition of {0!s}:"\ "expected {1!s} to be a class name"\ .format(name, root))
def root_app_implicit(expr): """If a term is of the form (..(f a0).. an), return the pair (f, [ai,..., ak]) where the ai...ak are the non-implicit arguments of f. Arguments: - `expr`: an expression """ r, args = root_app(expr) ty, _ = mvar_infer(r, ctxt=conf.current_ctxt()) non_implicit = [] i = 0 while ty.is_pi() and i < len(args): if not ty.info.implicit: non_implicit.append(args[i]) i += 1 ty = ty.body return (r, non_implicit)
def root_app_implicit(expr): """If a term is of the form (..(f a0).. an), return the pair (f, [ai,..., ak]) where the ai...ak are the non-implicit arguments of f. Arguments: - `expr`: an expression """ r, args = root_app(expr) ty, _ = mvar_infer(r, ctxt=current_ctxt()) non_implicit = [] i = 0 while ty.is_pi() and i < len(args): if not ty.info.implicit: non_implicit.append(args[i]) i += 1 ty = ty.body return (r, non_implicit)
def solve(self, goals, context): if len(goals) == 0: return [] else: hyps = goals[0].tele.types hyp_insts = [i for i in hyps if e.root_app(i)[0].info.is_class] ctxt_insts = context.to_list_rec('class_instances') for inst in hyp_insts + ctxt_insts: try: mvar_stack.new() return now(sub_mvar\ >> instance(inst)\ >> unify\ >> par(trytac(self))\ >> unify)\ .solve(goals, context) except TacticFailure: mvar_stack.free() goal_str = goals[0].prop mess = "No class instances for goal {0!s}".format(goal_str) raise TacticFailure(mess, self, goals)
def solve_ineqs(goals): """Solve a goal set consisting of subtyping constraints, possibly containing meta-variables. Arguments: - `goals`: a goal set """ goals.solve_with( trivial >> repeat(destruct >> trivial) >> par(trytac(sub_tac))) if goals.is_solved(): return goals else: ineqs = goals.goals c = ineqs[0].prop assert (c.is_sub()) #destruct>>trivial was unable to solve the constraint if not (c.lhs.is_mvar() or c.rhs.is_mvar()): #in this case, we have a higher-order unification problem, and #we just give up in hopes of finding an instance later (e.g. using #a type class) if e.root_app(c.lhs)[0].is_mvar() or \ e.root_app(c.rhs)[0].is_mvar(): return goals else: raise UnsolvabeConstr(c) else: if c.lhs.is_mvar(): m = c.lhs else: m = c.rhs assert (m.is_mvar()) lt, gt, other = split(m, ineqs) if len(lt) == 1 and len(gt) == 0: m.set_val(lt[0].prop.lhs) m_elim = other elif len(lt) == 0 and len(gt) == 1: m.set_val(gt[0].prop.rhs) mvar_stack.push(m) m_elim = other elif len(lt) == 1 and len(gt) == 1 and \ (lt[0].prop.lhs is gt[0].prop.rhs): m.set_val(lt[0].prop.lhs) mvar_stack.push(m) m_elim = other else: m_elim = cross(lt, gt) + other elim_goals = Goals('solve_ineqs', goals.context, goals=m_elim) solve_ineqs(elim_goals) lt = map(sub_in_goal, lt) gt = map(sub_in_goal, gt) if len(lt) != 0: lbs = [ineq.prop.lhs for ineq in lt] glb = max_type(lbs, goals.context) if not (glb is None): m.set_val(glb) mvar_stack.push(m) else: #Try the first possible solution m.set_val(lbs[0]) mvar_stack.push(m) elif len(gt) != 0: ubs = [ineq.prop.rhs for ineq in gt] lub = min_type(ubs, goals.context) if not (lub is None): m.set_val(lub) mvar_stack.push(m) else: #Try the first possible solution m.set_val(ubs[0]) mvar_stack.push(m) else: assert (False) goals.solve_with(sub_mvar >> trivial) if goals.is_solved(): return goals else: return solve_ineqs(goals)
def solve_ineqs(goals): """Solve a goal set consisting of subtyping constraints, possibly containing meta-variables. Arguments: - `goals`: a goal set """ goals.solve_with(trivial >> repeat(destruct >> trivial) >> par(trytac(sub_tac))) if goals.is_solved(): return goals else: ineqs = goals.goals c = ineqs[0].prop assert(c.is_sub()) #destruct>>trivial was unable to solve the constraint if not (c.lhs.is_mvar() or c.rhs.is_mvar()): #in this case, we have a higher-order unification problem, and #we just give up in hopes of finding an instance later (e.g. using #a type class) if e.root_app(c.lhs)[0].is_mvar() or \ e.root_app(c.rhs)[0].is_mvar(): return goals else: raise UnsolvabeConstr(c) else: if c.lhs.is_mvar(): m = c.lhs else: m = c.rhs assert(m.is_mvar()) lt, gt, other = split(m, ineqs) if len(lt) == 1 and len(gt) == 0: m.set_val(lt[0].prop.lhs) m_elim = other elif len(lt) == 0 and len(gt) == 1: m.set_val(gt[0].prop.rhs) mvar_stack.push(m) m_elim = other elif len(lt) == 1 and len(gt) == 1 and \ (lt[0].prop.lhs is gt[0].prop.rhs): m.set_val(lt[0].prop.lhs) mvar_stack.push(m) m_elim = other else: m_elim = cross(lt, gt) + other elim_goals = Goals('solve_ineqs', goals.context, goals=m_elim) solve_ineqs(elim_goals) lt = map(sub_in_goal, lt) gt = map(sub_in_goal, gt) if len(lt) != 0: lbs = [ineq.prop.lhs for ineq in lt] glb = max_type(lbs, goals.context) if not (glb is None): m.set_val(glb) mvar_stack.push(m) else: #Try the first possible solution m.set_val(lbs[0]) mvar_stack.push(m) elif len(gt) != 0: ubs = [ineq.prop.rhs for ineq in gt] lub = min_type(ubs, goals.context) if not (lub is None): m.set_val(lub) mvar_stack.push(m) else: #Try the first possible solution m.set_val(ubs[0]) mvar_stack.push(m) else: assert(False) goals.solve_with(sub_mvar >> trivial) if goals.is_solved(): return goals else: return solve_ineqs(goals)