예제 #1
0
    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
예제 #2
0
    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
예제 #3
0
    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