We need this feature for:
1) Defining nonlinear search patterns. Example: (?m <= ?m + 1)
2) Preprocessing recursive equations and support the pattern
refinement approach used in Agda. Example: in Agda, they accept
```
def append {A : Type} : Π (m n : nat), Vec A m -> Vec A n -> Vec A (m + n)
| m n nil ys := ys
| m n (cons m' x xs) ys := cons x (append m' n xs ys)
```
These equations have to be refined. For example, `m` has to be
replaced with `0` (in the first equation), and `succ m'` in the
second. To implement this kind of refinement, we need to convert
the pattern variables (local constants) into metavariables during
elaboration. Then, the unassigned metavariables become local constants
again. This preprocessing step will fix some of the issues on #1594.
To completely fix #1594, we will need yet another preprocessing step
which will implement "complete transition" used in the equation
compiler before we start elim_match.cpp
114 lines
3.6 KiB
C++
114 lines
3.6 KiB
C++
/*
|
|
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
Author: Leonardo de Moura
|
|
*/
|
|
#include <string>
|
|
#include "util/sstream.h"
|
|
#include "kernel/for_each_fn.h"
|
|
#include "library/choice.h"
|
|
#include "library/kernel_serializer.h"
|
|
|
|
namespace lean {
|
|
static name * g_choice_name = nullptr;
|
|
static std::string * g_choice_opcode = nullptr;
|
|
|
|
[[ noreturn ]] static void throw_ex() { throw exception("unexpected occurrence of 'choice' expression"); }
|
|
|
|
// We encode a 'choice' expression using a macro.
|
|
// This is a trick to avoid creating a new kind of expression.
|
|
// 'Choice' expressions are temporary objects used by the elaborator,
|
|
// and have no semantic significance.
|
|
class choice_macro_cell : public macro_definition_cell {
|
|
public:
|
|
virtual name get_name() const override { return *g_choice_name; }
|
|
// Choice expressions must be replaced with metavariables before invoking the type checker.
|
|
// Choice expressions cannot be exported. They are transient/auxiliary objects.
|
|
virtual expr check_type(expr const &, abstract_type_context &, bool) const override { throw_ex(); }
|
|
virtual optional<expr> expand(expr const &, abstract_type_context &) const override { throw_ex(); }
|
|
virtual void write(serializer & s) const override {
|
|
// we should be able to write choice expressions because of notation declarations
|
|
s.write_string(*g_choice_opcode);
|
|
}
|
|
};
|
|
|
|
static macro_definition * g_choice = nullptr;
|
|
expr mk_choice(unsigned num_es, expr const * es) {
|
|
lean_assert(num_es > 0);
|
|
if (num_es == 1)
|
|
return es[0];
|
|
else
|
|
return mk_macro(*g_choice, num_es, es);
|
|
}
|
|
|
|
list<list<name>> collect_choice_symbols(expr const & e) {
|
|
buffer<list<name>> r;
|
|
for_each(e, [&](expr const & e, unsigned) {
|
|
if (is_choice(e)) {
|
|
buffer<name> cs;
|
|
for (unsigned i = 0; i < get_num_choices(e); i++) {
|
|
expr const & c = get_app_fn(get_choice(e, i));
|
|
if (is_constant(c))
|
|
cs.push_back(const_name(c));
|
|
else if (is_local(c))
|
|
cs.push_back(mlocal_pp_name(c));
|
|
}
|
|
if (cs.size() > 1)
|
|
r.push_back(to_list(cs));
|
|
}
|
|
return true;
|
|
});
|
|
return to_list(r);
|
|
}
|
|
|
|
format pp_choice_symbols(expr const & e) {
|
|
list<list<name>> symbols = collect_choice_symbols(e);
|
|
if (symbols) {
|
|
format r;
|
|
bool first = true;
|
|
for (auto cs : symbols) {
|
|
format aux("overloads:");
|
|
for (auto s : cs)
|
|
aux += space() + format(s);
|
|
if (!first)
|
|
r += line();
|
|
r += aux;
|
|
first = false;
|
|
}
|
|
return r;
|
|
} else {
|
|
return format();
|
|
}
|
|
}
|
|
|
|
void initialize_choice() {
|
|
g_choice_name = new name("choice");
|
|
g_choice_opcode = new std::string("Choice");
|
|
g_choice = new macro_definition(new choice_macro_cell());
|
|
register_macro_deserializer(*g_choice_opcode,
|
|
[](deserializer &, unsigned num, expr const * args) {
|
|
return mk_choice(num, args);
|
|
});
|
|
}
|
|
|
|
void finalize_choice() {
|
|
delete g_choice;
|
|
delete g_choice_opcode;
|
|
delete g_choice_name;
|
|
}
|
|
|
|
bool is_choice(expr const & e) {
|
|
return is_macro(e) && macro_def(e) == *g_choice;
|
|
}
|
|
|
|
unsigned get_num_choices(expr const & e) {
|
|
lean_assert(is_choice(e));
|
|
return macro_num_args(e);
|
|
}
|
|
|
|
expr const & get_choice(expr const & e, unsigned i) {
|
|
lean_assert(is_choice(e));
|
|
return macro_arg(e, i);
|
|
}
|
|
}
|