feat(library/definitional/projection): define projections using auxiliary macro
This commit is contained in:
parent
c15bcf1354
commit
7de7c5b73d
3 changed files with 143 additions and 0 deletions
|
@ -6,13 +6,16 @@ Author: Leonardo de Moura
|
|||
*/
|
||||
#include "library/util.h"
|
||||
#include "library/definitional/equations.h"
|
||||
#include "library/definitional/projection.h"
|
||||
|
||||
namespace lean{
|
||||
void initialize_definitional_module() {
|
||||
initialize_equations();
|
||||
initialize_def_projection();
|
||||
}
|
||||
|
||||
void finalize_definitional_module() {
|
||||
finalize_def_projection();
|
||||
finalize_equations();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ Author: Leonardo de Moura
|
|||
#include "library/module.h"
|
||||
#include "library/util.h"
|
||||
#include "library/normalize.h"
|
||||
#include "library/kernel_serializer.h"
|
||||
#include "library/definitional/projection.h"
|
||||
|
||||
namespace lean {
|
||||
|
@ -51,6 +52,130 @@ static bool is_prop(expr type) {
|
|||
return is_sort(type) && is_zero(sort_level(type));
|
||||
}
|
||||
|
||||
|
||||
static name * g_projection_macro_name = nullptr;
|
||||
static std::string * g_projection_opcode = nullptr;
|
||||
|
||||
/** \brief Auxiliary macro used to implement projections efficiently.
|
||||
They bypass the recursor.
|
||||
|
||||
These macros are only used to speedup type checking when sending declarations to the kernel.
|
||||
During elaboration, we use a custom converter that never unfolds projections.
|
||||
*/
|
||||
class projection_macro_definition_cell : public macro_definition_cell {
|
||||
name m_I_name;
|
||||
name m_constructor_name;
|
||||
name m_proj_name;
|
||||
unsigned m_idx;
|
||||
level_param_names m_ps;
|
||||
expr m_type;
|
||||
expr m_val; // expanded form
|
||||
void check_macro(expr const & m) const {
|
||||
if (!is_macro(m) || macro_num_args(m) != 1)
|
||||
throw exception(sstream() << "invalid '" << m_proj_name
|
||||
<< "' projection macro, incorrect number of arguments");
|
||||
}
|
||||
|
||||
public:
|
||||
projection_macro_definition_cell(name const & I, name const & c, name const & p, unsigned i,
|
||||
level_param_names const & ps, expr const & type, expr const & val):
|
||||
m_I_name(I), m_constructor_name(c), m_proj_name(p), m_idx(i), m_ps(ps), m_type(type), m_val(val) {}
|
||||
|
||||
virtual name get_name() const { return m_proj_name; }
|
||||
virtual format pp(formatter const &) const { return format(m_proj_name); }
|
||||
virtual void display(std::ostream & out) const { out << m_proj_name; }
|
||||
virtual pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const {
|
||||
check_macro(m);
|
||||
environment const & env = ctx.env();
|
||||
constraint_seq cs;
|
||||
expr s = macro_arg(m, 0);
|
||||
expr s_t = ctx.whnf(ctx.check_type(s, cs, infer_only), cs);
|
||||
buffer<expr> I_args;
|
||||
expr const & I = get_app_args(s_t, I_args);
|
||||
if (!is_constant(I)) {
|
||||
// remark: this is not an issue since this macro should not be used during elaboration.
|
||||
throw_kernel_exception(env, sstream() << "projection macros do not support arbitrary terms "
|
||||
<< "containing metavariables yet (solution: use trust-level 0)", m);
|
||||
}
|
||||
|
||||
if (length(const_levels(I)) != length(m_ps))
|
||||
throw_kernel_exception(env, sstream() << "invalid projection application '" << m_proj_name
|
||||
<< "', incorrect number of universe parameters", m);
|
||||
expr t = instantiate_univ_params(m_type, m_ps, const_levels(I));
|
||||
I_args.push_back(s);
|
||||
return mk_pair(instantiate_rev(t, I_args.size(), I_args.data()), cs);
|
||||
}
|
||||
|
||||
virtual optional<expr> expand(expr const & m, extension_context & ctx) const {
|
||||
check_macro(m);
|
||||
expr const & s = macro_arg(m, 0);
|
||||
constraint_seq cs;
|
||||
expr new_s = ctx.whnf(s, cs);
|
||||
if (cs)
|
||||
return none_expr();
|
||||
buffer<expr> c_args;
|
||||
expr const & c = get_app_args(new_s, c_args);
|
||||
if (is_constant(c) && const_name(c) == m_constructor_name && m_idx < c_args.size()) {
|
||||
return some_expr(c_args[m_idx]);
|
||||
} else {
|
||||
// expand into recursor
|
||||
expr s_type = ctx.whnf(ctx.infer_type(s, cs), cs);
|
||||
if (cs)
|
||||
return none_expr();
|
||||
buffer<expr> args;
|
||||
expr const & I = get_app_args(s_type, args);
|
||||
if (!is_constant(I) || length(m_ps) != length(const_levels(I)))
|
||||
return none_expr();
|
||||
expr r = instantiate_univ_params(m_val, m_ps, const_levels(I));
|
||||
args.push_back(new_s);
|
||||
return some(instantiate_rev(r, args.size(), args.data()));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void write(serializer & s) const {
|
||||
s.write_string(*g_projection_opcode);
|
||||
s << m_I_name << m_constructor_name << m_proj_name << m_idx << m_ps << m_type << m_val;
|
||||
}
|
||||
|
||||
virtual bool operator==(macro_definition_cell const & other) const {
|
||||
if (auto other_ptr = dynamic_cast<projection_macro_definition_cell const *>(&other)) {
|
||||
return m_proj_name == other_ptr->m_proj_name;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual unsigned hash() const {
|
||||
return m_proj_name.hash();
|
||||
}
|
||||
};
|
||||
|
||||
static expr mk_projection_macro(name const & I, name const & c, name const & p, unsigned i,
|
||||
level_param_names const & ps, expr const & type, expr const & val, expr const & arg) {
|
||||
macro_definition m(new projection_macro_definition_cell(I, c, p, i, ps, type, val));
|
||||
return mk_macro(m, 1, &arg);
|
||||
}
|
||||
|
||||
void initialize_def_projection() {
|
||||
g_projection_macro_name = new name("projection");
|
||||
g_projection_opcode = new std::string("Proj");
|
||||
register_macro_deserializer(*g_projection_opcode,
|
||||
[](deserializer & d, unsigned num, expr const * args) {
|
||||
if (num != 1)
|
||||
throw corrupted_stream_exception();
|
||||
name I_name, c_name, proj_name; unsigned idx;
|
||||
level_param_names ps; expr type, val;
|
||||
d >> I_name >> c_name >> proj_name >> idx >> ps >> type >> val;
|
||||
return mk_projection_macro(I_name, c_name, proj_name, idx,
|
||||
ps, type, val, args[0]);
|
||||
});
|
||||
}
|
||||
|
||||
void finalize_def_projection() {
|
||||
delete g_projection_macro_name;
|
||||
delete g_projection_opcode;
|
||||
}
|
||||
|
||||
environment mk_projections(environment const & env, name const & n, buffer<name> const & proj_names,
|
||||
implicit_infer_kind infer_k, bool inst_implicit) {
|
||||
// Given an inductive datatype C A (where A represent parameters)
|
||||
|
@ -116,6 +241,18 @@ environment mk_projections(environment const & env, name const & n, buffer<name>
|
|||
expr proj_type = Pi(proj_args, result_type);
|
||||
proj_type = infer_implicit_params(proj_type, nparams, infer_k);
|
||||
expr proj_val = Fun(proj_args, rec_app);
|
||||
if (new_env.trust_lvl() > 0) {
|
||||
// use macros
|
||||
expr mval = proj_val;
|
||||
expr mtype = proj_type;
|
||||
for (unsigned i = 0; i < proj_args.size(); i++) {
|
||||
mval = binding_body(mval);
|
||||
mtype = binding_body(mtype);
|
||||
}
|
||||
proj_val = mk_projection_macro(n, inductive::intro_rule_name(intro), proj_name,
|
||||
nparams + i, lvl_params, mtype, mval, proj_args.back());
|
||||
proj_val = Fun(proj_args, proj_val);
|
||||
}
|
||||
bool use_conv_opt = false;
|
||||
declaration new_d = mk_definition(env, proj_name, lvl_params, proj_type, proj_val,
|
||||
use_conv_opt);
|
||||
|
|
|
@ -22,4 +22,7 @@ environment mk_projections(environment const & env, name const & n, buffer<name>
|
|||
implicit_infer_kind infer_k = implicit_infer_kind::Implicit, bool inst_implicit = false);
|
||||
environment mk_projections(environment const & env, name const & n,
|
||||
implicit_infer_kind infer_k = implicit_infer_kind::Implicit, bool inst_implicit = false);
|
||||
|
||||
void initialize_def_projection();
|
||||
void finalize_def_projection();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue