refactor(kernel): remove 'let'-expressions
We simulate it in the following way: 1- An opaque 'let'-expressions (let x : t := v in b) is encoded as ((fun (x : t), b) v) We also use a macro (let-macro) to mark this pattern. Thus, the pretty-printer knows how to display it correctly. 2- Transparent 'let'-expressions are eagerly expanded by the parser. Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
609aeae390
commit
603dafbaf7
32 changed files with 147 additions and 355 deletions
|
@ -20,6 +20,7 @@ static name g_colon(":");
|
|||
static name g_assign(":=");
|
||||
static name g_comma(",");
|
||||
static name g_fact("[fact]");
|
||||
static name g_inline("[inline]");
|
||||
static name g_from("from");
|
||||
static name g_using("using");
|
||||
static name g_then("then");
|
||||
|
@ -50,6 +51,25 @@ static expr parse_let_body(parser & p, pos_info const & pos) {
|
|||
}
|
||||
}
|
||||
|
||||
static expr mk_let(parser & p, name const & id, expr const & t, expr const & v, expr const & b, pos_info const & pos, binder_info const & bi) {
|
||||
expr l = p.save_pos(mk_lambda(id, t, b, bi), pos);
|
||||
return p.save_pos(mk_let_macro(p.save_pos(mk_app(l, v), pos)), pos);
|
||||
}
|
||||
|
||||
static void parse_let_modifiers(parser & p, bool & is_fact, bool & is_opaque) {
|
||||
while (true) {
|
||||
if (p.curr_is_token(g_fact)) {
|
||||
is_fact = true;
|
||||
p.next();
|
||||
} else if (p.curr_is_token(g_inline)) {
|
||||
is_opaque = false;
|
||||
p.next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static expr parse_let(parser & p, pos_info const & pos) {
|
||||
parser::local_scope scope1(p);
|
||||
if (p.parse_local_notation_decl()) {
|
||||
|
@ -57,12 +77,18 @@ static expr parse_let(parser & p, pos_info const & pos) {
|
|||
} else {
|
||||
auto pos = p.pos();
|
||||
name id = p.check_id_next("invalid let declaration, identifier expected");
|
||||
bool is_opaque = true;
|
||||
bool is_fact = false;
|
||||
expr type, value;
|
||||
parse_let_modifiers(p, is_fact, is_opaque);
|
||||
if (p.curr_is_token(g_assign)) {
|
||||
p.next();
|
||||
type = p.save_pos(mk_expr_placeholder(), pos);
|
||||
if (is_opaque)
|
||||
type = p.save_pos(mk_expr_placeholder(), pos);
|
||||
value = p.parse_expr();
|
||||
} else if (p.curr_is_token(g_colon)) {
|
||||
if (!is_opaque)
|
||||
throw parser_error("invalid let 'inline' declaration, explicit type must not be provided", p.pos());
|
||||
p.next();
|
||||
type = p.parse_expr();
|
||||
p.check_token_next(g_assign, "invalid declaration, ':=' expected");
|
||||
|
@ -72,20 +98,28 @@ static expr parse_let(parser & p, pos_info const & pos) {
|
|||
buffer<parameter> ps;
|
||||
auto lenv = p.parse_binders(ps);
|
||||
if (p.curr_is_token(g_colon)) {
|
||||
if (!is_opaque)
|
||||
throw parser_error("invalid let 'inline' declaration, explicit type must not be provided", p.pos());
|
||||
p.next();
|
||||
type = p.parse_scoped_expr(ps, lenv);
|
||||
} else {
|
||||
} else if (is_opaque) {
|
||||
type = p.save_pos(mk_expr_placeholder(), pos);
|
||||
}
|
||||
p.check_token_next(g_assign, "invalid let declaration, ':=' expected");
|
||||
value = p.parse_scoped_expr(ps, lenv);
|
||||
type = p.pi_abstract(ps, type);
|
||||
if (is_opaque)
|
||||
type = p.pi_abstract(ps, type);
|
||||
value = p.lambda_abstract(ps, value);
|
||||
}
|
||||
expr l = p.save_pos(mk_local(id, type), pos);
|
||||
p.add_local(l);
|
||||
expr body = abstract(parse_let_body(p, pos), l);
|
||||
return p.save_pos(mk_let(id, type, value, body), pos);
|
||||
if (is_opaque) {
|
||||
expr l = p.save_pos(mk_local(id, type), pos);
|
||||
p.add_local(l);
|
||||
expr body = abstract(parse_let_body(p, pos), l);
|
||||
return mk_let(p, id, type, value, body, pos, mk_contextual_info(is_fact));
|
||||
} else {
|
||||
p.add_local_expr(id, value, mk_contextual_info(false));
|
||||
return parse_let_body(p, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,7 +251,7 @@ static expr parse_show(parser & p, unsigned, expr const *, pos_info const & pos)
|
|||
expr prop = p.parse_expr();
|
||||
p.check_token_next(g_comma, "invalid 'show' declaration, ',' expected");
|
||||
expr proof = parse_proof(p, prop);
|
||||
return p.save_pos(mk_let(H_show, prop, proof, Var(0)), pos);
|
||||
return mk_let(p, H_show, prop, proof, Var(0), pos, mk_contextual_info(false));
|
||||
}
|
||||
|
||||
static expr parse_calc_expr(parser & p, unsigned, expr const *, pos_info const &) {
|
||||
|
|
|
@ -252,12 +252,6 @@ expr parser::copy_with_new_pos(expr const & e, pos_info p) {
|
|||
copy_with_new_pos(binding_domain(e), p),
|
||||
copy_with_new_pos(binding_body(e), p)),
|
||||
p);
|
||||
case expr_kind::Let:
|
||||
return save_pos(update_let(e,
|
||||
copy_with_new_pos(let_type(e), p),
|
||||
copy_with_new_pos(let_value(e), p),
|
||||
copy_with_new_pos(let_body(e), p)),
|
||||
p);
|
||||
case expr_kind::Macro: {
|
||||
buffer<expr> args;
|
||||
for (unsigned i = 0; i < macro_num_args(e); i++)
|
||||
|
|
|
@ -61,9 +61,4 @@ template<typename T> expr Pi(T const & locals, expr const & b) { return Pi(local
|
|||
inline expr Pi(expr const & local, expr const & b, binder_info const & bi = binder_info()) {
|
||||
return Pi(local_pp_name(local), mlocal_type(local), abstract(b, local), bi);
|
||||
}
|
||||
/**
|
||||
- \brief Create a Let expression (Let x := v in b), the term b is abstracted using abstract(b, x).
|
||||
-*/
|
||||
inline expr Let(name const & x, expr const & t, expr const & v, expr const & b) { return mk_let(x, t, v, abstract(b, mk_constant(x))); }
|
||||
inline expr Let(expr const & x, expr const & t, expr const & v, expr const & b) { return mk_let(named_expr_name(x), t, v, abstract(b, x)); }
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ struct default_converter : public converter {
|
|||
case expr_kind::Var: case expr_kind::Sort: case expr_kind::Meta: case expr_kind::Local:
|
||||
case expr_kind::Pi: case expr_kind::Constant:
|
||||
return e;
|
||||
case expr_kind::Lambda: case expr_kind::Macro: case expr_kind::Let: case expr_kind::App:
|
||||
case expr_kind::Lambda: case expr_kind::Macro: case expr_kind::App:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -109,9 +109,6 @@ struct default_converter : public converter {
|
|||
else
|
||||
r = e;
|
||||
break;
|
||||
case expr_kind::Let:
|
||||
r = whnf_core(instantiate(let_body(e), let_value(e)), c);
|
||||
break;
|
||||
case expr_kind::App: {
|
||||
buffer<expr> args;
|
||||
expr f0 = get_app_rev_args(e, args);
|
||||
|
@ -308,7 +305,7 @@ struct default_converter : public converter {
|
|||
case expr_kind::Meta:
|
||||
lean_unreachable(); // LCOV_EXCL_LINE
|
||||
case expr_kind::Var: case expr_kind::Local: case expr_kind::App:
|
||||
case expr_kind::Constant: case expr_kind::Macro: case expr_kind::Let:
|
||||
case expr_kind::Constant: case expr_kind::Macro:
|
||||
// We do not handle these cases in this method.
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -178,27 +178,6 @@ expr_sort::expr_sort(level const & l):
|
|||
}
|
||||
expr_sort::~expr_sort() {}
|
||||
|
||||
// Expr Let
|
||||
expr_let::expr_let(name const & n, expr const & t, expr const & v, expr const & b):
|
||||
expr_composite(expr_kind::Let, ::lean::hash(v.hash(), b.hash()),
|
||||
t.has_metavar() || v.has_metavar() || b.has_metavar(),
|
||||
t.has_local() || v.has_local() || b.has_local(),
|
||||
t.has_param_univ() || v.has_param_univ() || b.has_param_univ(),
|
||||
std::max({get_depth(t), get_depth(v), get_depth(b)}) + 1,
|
||||
std::max({get_free_var_range(t), get_free_var_range(v), dec(get_free_var_range(b))})),
|
||||
m_name(n),
|
||||
m_type(t),
|
||||
m_value(v),
|
||||
m_body(b) {
|
||||
}
|
||||
void expr_let::dealloc(buffer<expr_cell*> & todelete) {
|
||||
dec_ref(m_body, todelete);
|
||||
dec_ref(m_value, todelete);
|
||||
dec_ref(m_type, todelete);
|
||||
delete(this);
|
||||
}
|
||||
expr_let::~expr_let() {}
|
||||
|
||||
// Macro definition
|
||||
bool macro_definition_cell::lt(macro_definition_cell const &) const { return false; }
|
||||
bool macro_definition_cell::operator==(macro_definition_cell const & other) const { return typeid(*this) == typeid(other); }
|
||||
|
@ -297,7 +276,6 @@ expr mk_app(expr const & f, expr const & a) { return cache(expr(new expr_app(f,
|
|||
expr mk_binding(expr_kind k, name const & n, expr const & t, expr const & e, binder_info const & i) {
|
||||
return cache(expr(new expr_binding(k, n, t, e, i)));
|
||||
}
|
||||
expr mk_let(name const & n, expr const & t, expr const & v, expr const & e) { return cache(expr(new expr_let(n, t, v, e))); }
|
||||
expr mk_sort(level const & l) { return cache(expr(new expr_sort(l))); }
|
||||
// =======================================
|
||||
|
||||
|
@ -319,7 +297,6 @@ void expr_cell::dealloc() {
|
|||
case expr_kind::App: static_cast<expr_app*>(it)->dealloc(todo); break;
|
||||
case expr_kind::Lambda:
|
||||
case expr_kind::Pi: static_cast<expr_binding*>(it)->dealloc(todo); break;
|
||||
case expr_kind::Let: static_cast<expr_let*>(it)->dealloc(todo); break;
|
||||
}
|
||||
}
|
||||
} catch (std::bad_alloc&) {
|
||||
|
@ -443,7 +420,7 @@ unsigned get_depth(expr const & e) {
|
|||
case expr_kind::Meta: case expr_kind::Local:
|
||||
return 1;
|
||||
case expr_kind::Lambda: case expr_kind::Pi: case expr_kind::Macro:
|
||||
case expr_kind::App: case expr_kind::Let:
|
||||
case expr_kind::App:
|
||||
return static_cast<expr_composite*>(e.raw())->m_depth;
|
||||
}
|
||||
lean_unreachable(); // LCOV_EXCL_LINE
|
||||
|
@ -458,7 +435,7 @@ unsigned get_free_var_range(expr const & e) {
|
|||
case expr_kind::Meta: case expr_kind::Local:
|
||||
return get_free_var_range(mlocal_type(e));
|
||||
case expr_kind::Lambda: case expr_kind::Pi:
|
||||
case expr_kind::App: case expr_kind::Let:
|
||||
case expr_kind::App:
|
||||
case expr_kind::Macro:
|
||||
return static_cast<expr_composite*>(e.raw())->m_free_var_range;
|
||||
}
|
||||
|
@ -501,13 +478,6 @@ expr update_binding(expr const & e, expr const & new_domain, expr const & new_bo
|
|||
return e;
|
||||
}
|
||||
|
||||
expr update_let(expr const & e, expr const & new_type, expr const & new_val, expr const & new_body) {
|
||||
if (!is_eqp(let_type(e), new_type) || !is_eqp(let_value(e), new_val) || !is_eqp(let_body(e), new_body))
|
||||
return copy_tag(e, mk_let(let_name(e), new_type, new_val, new_body));
|
||||
else
|
||||
return e;
|
||||
}
|
||||
|
||||
expr update_mlocal(expr const & e, expr const & new_type) {
|
||||
if (is_eqp(mlocal_type(e), new_type))
|
||||
return e;
|
||||
|
@ -551,9 +521,9 @@ bool is_atomic(expr const & e) {
|
|||
return true;
|
||||
case expr_kind::Macro:
|
||||
return to_macro(e)->get_num_args() == 0;
|
||||
case expr_kind::App: case expr_kind::Let:
|
||||
case expr_kind::Meta: case expr_kind::Local:
|
||||
case expr_kind::Lambda: case expr_kind::Pi:
|
||||
case expr_kind::App: case expr_kind::Meta:
|
||||
case expr_kind::Local: case expr_kind::Lambda:
|
||||
case expr_kind::Pi:
|
||||
return false;
|
||||
}
|
||||
lean_unreachable(); // LCOV_EXCL_LINE
|
||||
|
@ -569,4 +539,37 @@ bool is_arrow(expr const & t) {
|
|||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
static name g_let("let");
|
||||
std::string const & get_let_macro_opcode() {
|
||||
static std::string g_let_macro_opcode("let");
|
||||
return g_let_macro_opcode;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief We use a macro to mark expressions that denote "let"-expressions.
|
||||
This marks have no real semantic meaning, but are used by Lean's pretty printer.
|
||||
*/
|
||||
class let_macro_definition_cell : public macro_definition_cell {
|
||||
static void check_macro(expr const & m) {
|
||||
if (!is_macro(m) || macro_num_args(m) != 1)
|
||||
throw exception("invalid 'let' macro");
|
||||
}
|
||||
public:
|
||||
virtual name get_name() const { return g_let; }
|
||||
virtual expr get_type(expr const & m, expr const * arg_types, extension_context &) const {
|
||||
check_macro(m);
|
||||
return arg_types[0];
|
||||
}
|
||||
virtual optional<expr> expand(expr const & m, extension_context &) const {
|
||||
check_macro(m);
|
||||
return some_expr(macro_arg(m, 0));
|
||||
}
|
||||
virtual void write(serializer & s) const { s.write_string(get_let_macro_opcode()); }
|
||||
};
|
||||
|
||||
static macro_definition g_let_macro_definition(new let_macro_definition_cell());
|
||||
expr mk_let_macro(expr const & e) { return mk_macro(g_let_macro_definition, 1, &e); }
|
||||
bool is_let_macro(expr const & e) { return is_macro(e) && macro_def(e) == g_let_macro_definition; }
|
||||
expr let_macro_arg(expr const & e) { lean_assert(is_let_macro(e)); return macro_arg(e, 0); }
|
||||
}
|
||||
|
|
|
@ -40,11 +40,10 @@ class expr;
|
|||
| App expr expr
|
||||
| Lambda name expr expr
|
||||
| Pi name expr expr
|
||||
| Let name expr expr expr
|
||||
|
||||
| Macro macro
|
||||
*/
|
||||
enum class expr_kind { Var, Sort, Constant, Meta, Local, App, Lambda, Pi, Let, Macro };
|
||||
enum class expr_kind { Var, Sort, Constant, Meta, Local, App, Lambda, Pi, Macro };
|
||||
class expr_cell {
|
||||
protected:
|
||||
// The bits of the following field mean:
|
||||
|
@ -132,7 +131,6 @@ public:
|
|||
friend expr mk_pair(expr const & f, expr const & s, expr const & t);
|
||||
friend expr mk_proj(bool fst, expr const & p);
|
||||
friend expr mk_binding(expr_kind k, name const & n, expr const & t, expr const & e, binder_info const & i);
|
||||
friend expr mk_let(name const & n, expr const & t, expr const & v, expr const & e);
|
||||
friend expr mk_macro(macro_definition const & m, unsigned num, expr const * args);
|
||||
|
||||
friend bool is_eqp(expr const & a, expr const & b) { return a.m_ptr == b.m_ptr; }
|
||||
|
@ -290,23 +288,6 @@ public:
|
|||
binder const & get_binder() const { return m_binder; }
|
||||
};
|
||||
|
||||
/** \brief Let expressions */
|
||||
class expr_let : public expr_composite {
|
||||
name m_name;
|
||||
expr m_type;
|
||||
expr m_value;
|
||||
expr m_body;
|
||||
friend class expr_cell;
|
||||
void dealloc(buffer<expr_cell*> & todelete);
|
||||
public:
|
||||
expr_let(name const & n, expr const & t, expr const & v, expr const & b);
|
||||
~expr_let();
|
||||
name const & get_name() const { return m_name; }
|
||||
expr const & get_type() const { return m_type; }
|
||||
expr const & get_value() const { return m_value; }
|
||||
expr const & get_body() const { return m_body; }
|
||||
};
|
||||
|
||||
/** \brief Sort */
|
||||
class expr_sort : public expr_cell {
|
||||
level m_level;
|
||||
|
@ -404,7 +385,6 @@ inline bool is_app(expr_cell * e) { return e->kind() == expr_kind::App;
|
|||
inline bool is_lambda(expr_cell * e) { return e->kind() == expr_kind::Lambda; }
|
||||
inline bool is_pi(expr_cell * e) { return e->kind() == expr_kind::Pi; }
|
||||
inline bool is_sort(expr_cell * e) { return e->kind() == expr_kind::Sort; }
|
||||
inline bool is_let(expr_cell * e) { return e->kind() == expr_kind::Let; }
|
||||
inline bool is_binding(expr_cell * e) { return is_lambda(e) || is_pi(e); }
|
||||
inline bool is_mlocal(expr_cell * e) { return is_metavar(e) || is_local(e); }
|
||||
|
||||
|
@ -417,7 +397,6 @@ inline bool is_app(expr const & e) { return e.kind() == expr_kind::App; }
|
|||
inline bool is_lambda(expr const & e) { return e.kind() == expr_kind::Lambda; }
|
||||
inline bool is_pi(expr const & e) { return e.kind() == expr_kind::Pi; }
|
||||
inline bool is_sort(expr const & e) { return e.kind() == expr_kind::Sort; }
|
||||
inline bool is_let(expr const & e) { return e.kind() == expr_kind::Let; }
|
||||
inline bool is_binding(expr const & e) { return is_lambda(e) || is_pi(e); }
|
||||
inline bool is_mlocal(expr const & e) { return is_metavar(e) || is_local(e); }
|
||||
|
||||
|
@ -455,7 +434,6 @@ inline expr mk_lambda(name const & n, expr const & t, expr const & e, binder_inf
|
|||
inline expr mk_pi(name const & n, expr const & t, expr const & e, binder_info const & i = binder_info()) {
|
||||
return mk_binding(expr_kind::Pi, n, t, e, i);
|
||||
}
|
||||
expr mk_let(name const & n, expr const & t, expr const & v, expr const & e);
|
||||
expr mk_sort(level const & l);
|
||||
|
||||
/** \brief Return <tt>Pi(x.{sz-1}, domain[sz-1], ..., Pi(x.{0}, domain[0], range)...)</tt> */
|
||||
|
@ -517,7 +495,6 @@ inline expr_var * to_var(expr_cell * e) { lean_assert(is_var(e));
|
|||
inline expr_const * to_constant(expr_cell * e) { lean_assert(is_constant(e)); return static_cast<expr_const*>(e); }
|
||||
inline expr_app * to_app(expr_cell * e) { lean_assert(is_app(e)); return static_cast<expr_app*>(e); }
|
||||
inline expr_binding * to_binding(expr_cell * e) { lean_assert(is_binding(e)); return static_cast<expr_binding*>(e); }
|
||||
inline expr_let * to_let(expr_cell * e) { lean_assert(is_let(e)); return static_cast<expr_let*>(e); }
|
||||
inline expr_sort * to_sort(expr_cell * e) { lean_assert(is_sort(e)); return static_cast<expr_sort*>(e); }
|
||||
inline expr_mlocal * to_mlocal(expr_cell * e) { lean_assert(is_mlocal(e)); return static_cast<expr_mlocal*>(e); }
|
||||
inline expr_local * to_local(expr_cell * e) { lean_assert(is_local(e)); return static_cast<expr_local*>(e); }
|
||||
|
@ -528,7 +505,6 @@ inline expr_var * to_var(expr const & e) { return to_var(e.raw()
|
|||
inline expr_const * to_constant(expr const & e) { return to_constant(e.raw()); }
|
||||
inline expr_app * to_app(expr const & e) { return to_app(e.raw()); }
|
||||
inline expr_binding * to_binding(expr const & e) { return to_binding(e.raw()); }
|
||||
inline expr_let * to_let(expr const & e) { return to_let(e.raw()); }
|
||||
inline expr_sort * to_sort(expr const & e) { return to_sort(e.raw()); }
|
||||
inline expr_mlocal * to_mlocal(expr const & e) { return to_mlocal(e.raw()); }
|
||||
inline expr_mlocal * to_metavar(expr const & e) { return to_metavar(e.raw()); }
|
||||
|
@ -557,10 +533,6 @@ inline expr const & binding_body(expr_cell * e) { return to_binding(e
|
|||
inline binder_info const & binding_info(expr_cell * e) { return to_binding(e)->get_info(); }
|
||||
inline binder const & binding_binder(expr_cell * e) { return to_binding(e)->get_binder(); }
|
||||
inline level const & sort_level(expr_cell * e) { return to_sort(e)->get_level(); }
|
||||
inline name const & let_name(expr_cell * e) { return to_let(e)->get_name(); }
|
||||
inline expr const & let_value(expr_cell * e) { return to_let(e)->get_value(); }
|
||||
inline expr const & let_type(expr_cell * e) { return to_let(e)->get_type(); }
|
||||
inline expr const & let_body(expr_cell * e) { return to_let(e)->get_body(); }
|
||||
inline name const & mlocal_name(expr_cell * e) { return to_mlocal(e)->get_name(); }
|
||||
inline expr const & mlocal_type(expr_cell * e) { return to_mlocal(e)->get_type(); }
|
||||
|
||||
|
@ -582,10 +554,6 @@ inline expr const & binding_body(expr const & e) { return to_binding(
|
|||
inline binder_info const & binding_info(expr const & e) { return to_binding(e)->get_info(); }
|
||||
inline binder const & binding_binder(expr const & e) { return to_binding(e)->get_binder(); }
|
||||
inline level const & sort_level(expr const & e) { return to_sort(e)->get_level(); }
|
||||
inline name const & let_name(expr const & e) { return to_let(e)->get_name(); }
|
||||
inline expr const & let_value(expr const & e) { return to_let(e)->get_value(); }
|
||||
inline expr const & let_type(expr const & e) { return to_let(e)->get_type(); }
|
||||
inline expr const & let_body(expr const & e) { return to_let(e)->get_body(); }
|
||||
inline name const & mlocal_name(expr const & e) { return to_mlocal(e)->get_name(); }
|
||||
inline expr const & mlocal_type(expr const & e) { return to_mlocal(e)->get_type(); }
|
||||
inline name const & local_pp_name(expr const & e) { return to_local(e)->get_pp_name(); }
|
||||
|
@ -666,12 +634,19 @@ expr update_app(expr const & e, expr const & new_fn, expr const & new_arg);
|
|||
expr update_rev_app(expr const & e, unsigned num, expr const * new_args);
|
||||
template<typename C> expr update_rev_app(expr const & e, C const & c) { return update_rev_app(e, c.size(), c.data()); }
|
||||
expr update_binding(expr const & e, expr const & new_domain, expr const & new_body);
|
||||
expr update_let(expr const & e, expr const & new_type, expr const & new_val, expr const & new_body);
|
||||
expr update_mlocal(expr const & e, expr const & new_type);
|
||||
expr update_sort(expr const & e, level const & new_level);
|
||||
expr update_constant(expr const & e, levels const & new_levels);
|
||||
expr update_macro(expr const & e, unsigned num, expr const * args);
|
||||
// =======================================
|
||||
|
||||
// =======================================
|
||||
// Auxiliary macro for "marking" let-expressions
|
||||
expr mk_let_macro(expr const & e);
|
||||
bool is_let_macro(expr const & e);
|
||||
expr let_macro_arg(expr const & e);
|
||||
std::string const & get_let_macro_opcode();
|
||||
// =======================================
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, expr const & e);
|
||||
}
|
||||
|
|
|
@ -58,12 +58,6 @@ bool expr_eq_fn::apply(expr const & a, expr const & b) {
|
|||
return false;
|
||||
}
|
||||
return true;
|
||||
case expr_kind::Let:
|
||||
m_counter++;
|
||||
return
|
||||
apply(let_type(a), let_type(b)) &&
|
||||
apply(let_value(a), let_value(b)) &&
|
||||
apply(let_body(a), let_body(b));
|
||||
}
|
||||
lean_unreachable(); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
|
|
@ -64,11 +64,6 @@ void for_each_fn::apply(expr const & e, unsigned offset) {
|
|||
todo.emplace_back(binding_body(e), offset + 1);
|
||||
todo.emplace_back(binding_domain(e), offset);
|
||||
goto begin_loop;
|
||||
case expr_kind::Let:
|
||||
todo.emplace_back(let_body(e), offset + 1);
|
||||
todo.emplace_back(let_value(e), offset);
|
||||
todo.emplace_back(let_type(e), offset);
|
||||
goto begin_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,13 +37,6 @@ std::pair<expr, expr> binding_body_fresh(expr const & b, bool preserve_type) {
|
|||
return mk_pair(instantiate(binding_body(b), c), c);
|
||||
}
|
||||
|
||||
std::pair<expr, expr> let_body_fresh(expr const & l, bool preserve_type) {
|
||||
lean_assert(is_let(l));
|
||||
name n = pick_unused_name(let_body(l), let_name(l));
|
||||
expr c = mk_local(n, preserve_type ? let_type(l) : expr());
|
||||
return mk_pair(instantiate(let_body(l), c), c);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Very basic printer for expressions.
|
||||
It is mainly used when debugging code.
|
||||
|
@ -66,10 +59,35 @@ struct print_expr_fn {
|
|||
}
|
||||
}
|
||||
|
||||
bool print_let(expr const & a) {
|
||||
if (!is_let_macro(a))
|
||||
return false;
|
||||
expr l = let_macro_arg(a);
|
||||
if (!is_app(l) || !is_lambda(app_fn(l)))
|
||||
return false;
|
||||
name n = binding_name(app_fn(l));
|
||||
expr t = binding_domain(app_fn(l));
|
||||
expr b = binding_body(app_fn(l));
|
||||
expr v = app_arg(l);
|
||||
n = pick_unused_name(b, n);
|
||||
expr c = mk_local(n, expr());
|
||||
b = instantiate(b, c);
|
||||
out() << "let " << c;
|
||||
out() << " : ";
|
||||
print(t);
|
||||
out() << " := ";
|
||||
print(v);
|
||||
out() << " in ";
|
||||
print_child(b);
|
||||
return true;
|
||||
}
|
||||
|
||||
void print_macro(expr const & a) {
|
||||
macro_def(a).display(out());
|
||||
for (unsigned i = 0; i < macro_num_args(a); i++) {
|
||||
out() << " "; print_child(macro_arg(a, i));
|
||||
if (!print_let(a)) {
|
||||
macro_def(a).display(out());
|
||||
for (unsigned i = 0; i < macro_num_args(a); i++) {
|
||||
out() << " "; print_child(macro_arg(a, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,19 +121,6 @@ struct print_expr_fn {
|
|||
return print_child(a);
|
||||
}
|
||||
|
||||
void print_let(expr const & a) {
|
||||
auto p = let_body_fresh(a);
|
||||
expr const & b = p.first;
|
||||
expr const & n = p.second;
|
||||
out() << "let " << n;
|
||||
out() << " : ";
|
||||
print(let_type(a));
|
||||
out() << " := ";
|
||||
print(let_value(a));
|
||||
out() << " in ";
|
||||
print_child(b);
|
||||
}
|
||||
|
||||
void print_binding(char const * bname, expr e) {
|
||||
expr_kind k = e.kind();
|
||||
out() << bname;
|
||||
|
@ -190,9 +195,6 @@ struct print_expr_fn {
|
|||
print_arrow_body(lower_free_vars(binding_body(a), 1));
|
||||
}
|
||||
break;
|
||||
case expr_kind::Let:
|
||||
print_let(a);
|
||||
break;
|
||||
case expr_kind::Sort:
|
||||
print_sort(a);
|
||||
break;
|
||||
|
|
|
@ -69,9 +69,6 @@ protected:
|
|||
case expr_kind::Lambda: case expr_kind::Pi:
|
||||
result = apply(binding_domain(e), offset) || apply(binding_body(e), offset + 1);
|
||||
break;
|
||||
case expr_kind::Let:
|
||||
result = apply(let_type(e), offset) || apply(let_value(e), offset) || apply(let_body(e), offset + 1);
|
||||
break;
|
||||
case expr_kind::Macro:
|
||||
for (unsigned i = 0; i < macro_num_args(e); i++) {
|
||||
if (apply(macro_arg(e, i), offset)) {
|
||||
|
|
|
@ -101,19 +101,11 @@ expr replace_fn::operator()(expr const & e) {
|
|||
r = update_binding(e, rs(-2), rs(-1));
|
||||
pop_rs(2);
|
||||
break;
|
||||
case expr_kind::Let:
|
||||
if (check_index(f, 0) && !visit(let_type(e), offset))
|
||||
goto begin_loop;
|
||||
if (check_index(f, 1) && !visit(let_value(e), offset))
|
||||
goto begin_loop;
|
||||
if (check_index(f, 2) && !visit(let_body(e), offset + 1))
|
||||
goto begin_loop;
|
||||
r = update_let(e, rs(-3), rs(-2), rs(-1));
|
||||
pop_rs(3);
|
||||
break;
|
||||
case expr_kind::Macro:
|
||||
while (f.m_index < macro_num_args(e)) {
|
||||
if (!visit(macro_arg(e, f.m_index), offset))
|
||||
unsigned idx = f.m_index;
|
||||
f.m_index++;
|
||||
if (!visit(macro_arg(e, idx), offset))
|
||||
goto begin_loop;
|
||||
}
|
||||
r = update_macro(e, macro_num_args(e), &rs(-macro_num_args(e)));
|
||||
|
|
|
@ -30,13 +30,6 @@ expr replace_visitor::visit_binding(expr const & e) {
|
|||
}
|
||||
expr replace_visitor::visit_lambda(expr const & e) { return visit_binding(e); }
|
||||
expr replace_visitor::visit_pi(expr const & e) { return visit_binding(e); }
|
||||
expr replace_visitor::visit_let(expr const & e) {
|
||||
lean_assert(is_let(e));
|
||||
expr new_t = visit(let_type(e));
|
||||
expr new_v = visit(let_value(e));
|
||||
expr new_b = visit(let_body(e));
|
||||
return update_let(e, new_t, new_v, new_b);
|
||||
}
|
||||
expr replace_visitor::visit_macro(expr const & e) {
|
||||
lean_assert(is_macro(e));
|
||||
buffer<expr> new_args;
|
||||
|
@ -69,7 +62,6 @@ expr replace_visitor::visit(expr const & e) {
|
|||
case expr_kind::App: return save_result(e, visit_app(e), shared);
|
||||
case expr_kind::Lambda: return save_result(e, visit_lambda(e), shared);
|
||||
case expr_kind::Pi: return save_result(e, visit_pi(e), shared);
|
||||
case expr_kind::Let: return save_result(e, visit_let(e), shared);
|
||||
}
|
||||
|
||||
lean_unreachable(); // LCOV_EXCL_LINE
|
||||
|
|
|
@ -30,7 +30,6 @@ protected:
|
|||
virtual expr visit_binding(expr const &);
|
||||
virtual expr visit_lambda(expr const &);
|
||||
virtual expr visit_pi(expr const &);
|
||||
virtual expr visit_let(expr const &);
|
||||
virtual expr visit(expr const &);
|
||||
public:
|
||||
expr operator()(expr const & e) { return visit(e); }
|
||||
|
|
|
@ -203,20 +203,6 @@ expr type_checker::ensure_pi_core(expr e, expr const & s) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create a justification for a let definition type mismatch,
|
||||
\c e is the let expression, and \c val_type is the type inferred for the let value.
|
||||
*/
|
||||
justification type_checker::mk_let_mismatch_jst(expr const & e, expr const & val_type) {
|
||||
lean_assert(is_let(e));
|
||||
return mk_justification(e,
|
||||
[=](formatter const & fmt, options const & o, substitution const & subst) {
|
||||
return pp_def_type_mismatch(fmt, m_env, o, let_name(e),
|
||||
subst.instantiate_metavars_wo_jst(let_type(e)),
|
||||
subst.instantiate_metavars_wo_jst(val_type));
|
||||
});
|
||||
}
|
||||
|
||||
static constexpr char const * g_macro_error_msg = "failed to type check macro expansion";
|
||||
|
||||
justification type_checker::mk_macro_jst(expr const & e) {
|
||||
|
@ -343,23 +329,7 @@ expr type_checker::infer_type_core(expr const & e, bool infer_only) {
|
|||
}
|
||||
r = instantiate(binding_body(f_type), app_arg(e));
|
||||
break;
|
||||
}
|
||||
case expr_kind::Let:
|
||||
if (!infer_only) {
|
||||
ensure_sort_core(infer_type_core(let_type(e), infer_only), let_type(e));
|
||||
expr val_type = infer_type_core(let_value(e), infer_only);
|
||||
simple_delayed_justification jst([=]() { return mk_let_mismatch_jst(e, val_type); });
|
||||
if (!is_def_eq(val_type, let_type(e), jst)) {
|
||||
environment env = m_env;
|
||||
throw_kernel_exception(env, e,
|
||||
[=](formatter const & fmt, options const & o) {
|
||||
return pp_def_type_mismatch(fmt, env, o, let_name(e), let_type(e), val_type);
|
||||
});
|
||||
}
|
||||
}
|
||||
r = infer_type_core(instantiate(let_body(e), let_value(e)), infer_only);
|
||||
break;
|
||||
}
|
||||
}}
|
||||
|
||||
if (m_memoize)
|
||||
m_infer_type_cache[infer_only].insert(mk_pair(e, r));
|
||||
|
|
|
@ -76,7 +76,6 @@ class type_checker {
|
|||
bool meta_to_telescope_core(expr const & e, buffer<expr> & telescope, buffer<optional<expr>> & locals);
|
||||
expr ensure_sort_core(expr e, expr const & s);
|
||||
expr ensure_pi_core(expr e, expr const & s);
|
||||
justification mk_let_mismatch_jst(expr const & e, expr const & val_type);
|
||||
justification mk_macro_jst(expr const & e);
|
||||
void check_level(level const & l, expr const & s);
|
||||
expr infer_type_core(expr const & e, bool infer_only);
|
||||
|
|
|
@ -19,7 +19,6 @@ expr copy(expr const & a) {
|
|||
case expr_kind::App: return mk_app(app_fn(a), app_arg(a));
|
||||
case expr_kind::Lambda: return mk_lambda(binding_name(a), binding_domain(a), binding_body(a), binding_info(a));
|
||||
case expr_kind::Pi: return mk_pi(binding_name(a), binding_domain(a), binding_body(a), binding_info(a));
|
||||
case expr_kind::Let: return mk_let(let_name(a), let_type(a), let_value(a), let_body(a));
|
||||
case expr_kind::Meta: return mk_metavar(mlocal_name(a), mlocal_type(a));
|
||||
case expr_kind::Local: return mk_local(mlocal_name(a), local_pp_name(a), mlocal_type(a));
|
||||
}
|
||||
|
|
|
@ -40,14 +40,6 @@ bool is_lt(expr const & a, expr const & b, bool use_hash) {
|
|||
return is_lt(binding_body(a), binding_body(b), use_hash);
|
||||
case expr_kind::Sort:
|
||||
return is_lt(sort_level(a), sort_level(b), use_hash);
|
||||
case expr_kind::Let:
|
||||
if (let_type(a) != let_type(b)) {
|
||||
return is_lt(let_type(a), let_type(b), use_hash);
|
||||
} else if (let_value(a) != let_value(b)){
|
||||
return is_lt(let_value(a), let_value(b), use_hash);
|
||||
} else {
|
||||
return is_lt(let_body(a), let_body(b), use_hash);
|
||||
}
|
||||
case expr_kind::Local: case expr_kind::Meta:
|
||||
if (mlocal_name(a) != mlocal_name(b))
|
||||
return mlocal_name(a) < mlocal_name(b);
|
||||
|
|
|
@ -325,13 +325,6 @@ expr & to_macro_app(lua_State * L, int idx) {
|
|||
return r;
|
||||
}
|
||||
|
||||
expr & to_let(lua_State * L, int idx) {
|
||||
expr & r = to_expr(L, idx);
|
||||
if (!is_let(r))
|
||||
throw exception(sstream() << "arg #" << idx << " must be a let-expression");
|
||||
return r;
|
||||
}
|
||||
|
||||
static int expr_tostring(lua_State * L) {
|
||||
std::ostringstream out;
|
||||
formatter fmt = get_global_formatter(L);
|
||||
|
@ -383,16 +376,6 @@ static int expr_mk_arrow(lua_State * L) {
|
|||
r = mk_arrow(to_expr(L, i), r);
|
||||
return push_expr(L, r);
|
||||
}
|
||||
static int expr_mk_let(lua_State * L) { return push_expr(L, mk_let(to_name_ext(L, 1), to_expr(L, 2), to_expr(L, 3), to_expr(L, 4))); }
|
||||
|
||||
static expr get_expr_from_table(lua_State * L, int t, int i) {
|
||||
lua_pushvalue(L, t); // push table to the top
|
||||
lua_pushinteger(L, i);
|
||||
lua_gettable(L, -2);
|
||||
expr r = to_expr(L, -1);
|
||||
lua_pop(L, 2); // remove table and value
|
||||
return r;
|
||||
}
|
||||
|
||||
static void throw_invalid_binder_table(int t) {
|
||||
#define VALID_FORMS "local_name, {local_name, bool}, {expr, expr}, {expr, expr, bool}, or {expr, expr, binder_info}, each entry represents a binder, the first expression in each entry must be a (local) constant, the second expression is the type, the optional Boolean can be used to mark implicit arguments."
|
||||
|
@ -519,51 +502,6 @@ static int expr_mk_local(lua_State * L) {
|
|||
}
|
||||
static int expr_get_kind(lua_State * L) { return push_integer(L, static_cast<int>(to_expr(L, 1).kind())); }
|
||||
|
||||
// t is a table of pairs {{a1, b1, c1}, ..., {ak, bk, ck}}
|
||||
// ai, bi and ci are expressions
|
||||
static std::tuple<expr, expr, expr> get_expr_triple_from_table(lua_State * L, int t, int i) {
|
||||
lua_pushvalue(L, t); // push table on the top
|
||||
lua_pushinteger(L, i);
|
||||
lua_gettable(L, -2); // now table {ai, bi, ci} is on the top
|
||||
if (!lua_istable(L, -1) || objlen(L, -1) != 3)
|
||||
throw exception(sstream() << "arg #" << t << " must be of the form '{{expr, expr, expr}, ...}'");
|
||||
expr ai = get_expr_from_table(L, -1, 1);
|
||||
expr bi = get_expr_from_table(L, -1, 2);
|
||||
expr ci = get_expr_from_table(L, -1, 3);
|
||||
lua_pop(L, 2); // pop table {ai, bi, ci} and t from stack
|
||||
return std::make_tuple(ai, bi, ci);
|
||||
}
|
||||
|
||||
static int expr_let(lua_State * L) {
|
||||
int nargs = lua_gettop(L);
|
||||
if (nargs < 2)
|
||||
throw exception("function must have at least 2 arguments");
|
||||
if (nargs == 2) {
|
||||
if (!lua_istable(L, 1))
|
||||
throw exception("function expects arg #1 to be of the form '{{expr, expr, expr}, ...}'");
|
||||
int len = objlen(L, 1);
|
||||
if (len == 0)
|
||||
throw exception("function expects arg #1 to be a non-empty table");
|
||||
expr r = to_expr(L, 2);
|
||||
for (int i = len; i >= 1; i--) {
|
||||
auto p = get_expr_triple_from_table(L, 1, i);
|
||||
r = Let(std::get<0>(p), std::get<1>(p), std::get<2>(p), r);
|
||||
}
|
||||
return push_expr(L, r);
|
||||
} else {
|
||||
if ((nargs - 1) % 3 != 0)
|
||||
throw exception("function must have 3*n + 1 arguments");
|
||||
expr r = to_expr(L, nargs);
|
||||
for (int i = nargs - 1; i >= 1; i-=3) {
|
||||
if (is_expr(L, i - 2))
|
||||
r = Let(to_expr(L, i - 2), to_expr(L, i - 1), to_expr(L, i), r);
|
||||
else
|
||||
r = Let(to_name_ext(L, i - 2), to_expr(L, i - 1), to_expr(L, i), r);
|
||||
}
|
||||
return push_expr(L, r);
|
||||
}
|
||||
}
|
||||
|
||||
#define EXPR_PRED(P) static int expr_ ## P(lua_State * L) { check_num_args(L, 1); return push_boolean(L, P(to_expr(L, 1))); }
|
||||
|
||||
EXPR_PRED(is_constant)
|
||||
|
@ -572,7 +510,6 @@ EXPR_PRED(is_app)
|
|||
EXPR_PRED(is_lambda)
|
||||
EXPR_PRED(is_pi)
|
||||
EXPR_PRED(is_binding)
|
||||
EXPR_PRED(is_let)
|
||||
EXPR_PRED(is_macro)
|
||||
EXPR_PRED(is_metavar)
|
||||
EXPR_PRED(is_local)
|
||||
|
@ -600,8 +537,6 @@ static int expr_fields(lua_State * L) {
|
|||
case expr_kind::Lambda:
|
||||
case expr_kind::Pi:
|
||||
push_name(L, binding_name(e)); push_expr(L, binding_domain(e)); push_expr(L, binding_body(e)); push_binder_info(L, binding_info(e)); return 4;
|
||||
case expr_kind::Let:
|
||||
push_name(L, let_name(e)); push_expr(L, let_type(e)); push_expr(L, let_value(e)); push_expr(L, let_body(e)); return 4;
|
||||
case expr_kind::Meta:
|
||||
case expr_kind::Local:
|
||||
push_name(L, mlocal_name(e)); push_expr(L, mlocal_type(e)); return 2;
|
||||
|
@ -728,11 +663,6 @@ static int binding_domain(lua_State * L) { return push_expr(L, binding_domain(to
|
|||
static int binding_body(lua_State * L) { return push_expr(L, binding_body(to_binding(L, 1))); }
|
||||
static int binding_info(lua_State * L) { return push_binder_info(L, binding_info(to_binding(L, 1))); }
|
||||
|
||||
static int let_name(lua_State * L) { return push_name(L, let_name(to_let(L, 1))); }
|
||||
static int let_type(lua_State * L) { return push_expr(L, let_type(to_let(L, 1))); }
|
||||
static int let_value(lua_State * L) { return push_expr(L, let_value(to_let(L, 1))); }
|
||||
static int let_body(lua_State * L) { return push_expr(L, let_body(to_let(L, 1))); }
|
||||
|
||||
static int expr_occurs(lua_State * L) { return push_boolean(L, occurs(to_expr(L, 1), to_expr(L, 2))); }
|
||||
static int expr_is_eqp(lua_State * L) { return push_boolean(L, is_eqp(to_expr(L, 1), to_expr(L, 2))); }
|
||||
static int expr_hash(lua_State * L) { return push_integer(L, to_expr(L, 1).hash()); }
|
||||
|
@ -773,7 +703,6 @@ static const struct luaL_Reg expr_m[] = {
|
|||
{"is_lambda", safe_function<expr_is_lambda>},
|
||||
{"is_pi", safe_function<expr_is_pi>},
|
||||
{"is_binding", safe_function<expr_is_binding>},
|
||||
{"is_let", safe_function<expr_is_let>},
|
||||
{"is_macro", safe_function<expr_is_macro>},
|
||||
{"is_meta", safe_function<expr_is_meta>},
|
||||
{"has_free_vars", safe_function<expr_has_free_vars>},
|
||||
|
@ -790,10 +719,6 @@ static const struct luaL_Reg expr_m[] = {
|
|||
{"binding_domain", safe_function<binding_domain>},
|
||||
{"binding_body", safe_function<binding_body>},
|
||||
{"binding_info", safe_function<binding_info>},
|
||||
{"let_name", safe_function<let_name>},
|
||||
{"let_type", safe_function<let_type>},
|
||||
{"let_value", safe_function<let_value>},
|
||||
{"let_body", safe_function<let_body>},
|
||||
{"macro_def", safe_function<macro_def>},
|
||||
{"macro_num_args", safe_function<macro_num_args>},
|
||||
{"macro_arg", safe_function<macro_arg>},
|
||||
|
@ -832,12 +757,10 @@ static void open_expr(lua_State * L) {
|
|||
SET_GLOBAL_FUN(expr_mk_lambda, "mk_lambda");
|
||||
SET_GLOBAL_FUN(expr_mk_pi, "mk_pi");
|
||||
SET_GLOBAL_FUN(expr_mk_arrow, "mk_arrow");
|
||||
SET_GLOBAL_FUN(expr_mk_let, "mk_let");
|
||||
SET_GLOBAL_FUN(expr_mk_macro, "mk_macro");
|
||||
SET_GLOBAL_FUN(expr_fun, "fun");
|
||||
SET_GLOBAL_FUN(expr_fun, "Fun");
|
||||
SET_GLOBAL_FUN(expr_pi, "Pi");
|
||||
SET_GLOBAL_FUN(expr_let, "Let");
|
||||
SET_GLOBAL_FUN(expr_mk_sort, "mk_sort");
|
||||
SET_GLOBAL_FUN(expr_mk_metavar, "mk_metavar");
|
||||
SET_GLOBAL_FUN(expr_mk_local, "mk_local");
|
||||
|
@ -861,7 +784,6 @@ static void open_expr(lua_State * L) {
|
|||
SET_ENUM("App", expr_kind::App);
|
||||
SET_ENUM("Lambda", expr_kind::Lambda);
|
||||
SET_ENUM("Pi", expr_kind::Pi);
|
||||
SET_ENUM("Let", expr_kind::Let);
|
||||
SET_ENUM("Macro", expr_kind::Macro);
|
||||
lua_setglobal(L, "expr_kind");
|
||||
}
|
||||
|
|
|
@ -159,9 +159,6 @@ class expr_serializer : public object_serializer<expr, expr_hash_alloc, expr_eqp
|
|||
case expr_kind::Lambda: case expr_kind::Pi:
|
||||
s << binding_name(a) << binding_info(a); write_core(binding_domain(a)); write_core(binding_body(a));
|
||||
break;
|
||||
case expr_kind::Let:
|
||||
s << let_name(a); write_core(let_type(a)); write_core(let_value(a)); write_core(let_body(a));
|
||||
break;
|
||||
case expr_kind::Meta:
|
||||
s << mlocal_name(a); write_core(mlocal_type(a));
|
||||
break;
|
||||
|
@ -215,12 +212,6 @@ public:
|
|||
}
|
||||
case expr_kind::Lambda: case expr_kind::Pi:
|
||||
return read_binding(k);
|
||||
case expr_kind::Let: {
|
||||
name n = read_name(d);
|
||||
expr t = read();
|
||||
expr v = read();
|
||||
return mk_let(n, t, v, read());
|
||||
}
|
||||
case expr_kind::Meta: {
|
||||
name n = read_name(d);
|
||||
return mk_metavar(n, read());
|
||||
|
@ -341,4 +332,13 @@ inductive_decls read_inductive_decls(deserializer & d) {
|
|||
}
|
||||
return inductive_decls(ps, num_params, to_list(decls.begin(), decls.end()));
|
||||
}
|
||||
|
||||
|
||||
static register_macro_deserializer_fn
|
||||
let_macro_des_fn(get_let_macro_opcode(),
|
||||
[](deserializer &, unsigned num, expr const * args) {
|
||||
if (num != 1)
|
||||
throw_corrupted_file();
|
||||
return mk_let_macro(args[0]);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -38,9 +38,6 @@ struct max_sharing_fn::imp {
|
|||
case expr_kind::Lambda: case expr_kind::Pi:
|
||||
res = update_binding(a, apply(binding_domain(a)), apply(binding_body(a)));
|
||||
break;
|
||||
case expr_kind::Let:
|
||||
res = update_let(a, apply(let_type(a)), apply(let_value(a)), apply(let_body(a)));
|
||||
break;
|
||||
case expr_kind::Meta: case expr_kind::Local:
|
||||
res = update_mlocal(a, apply(mlocal_type(a)));
|
||||
break;
|
||||
|
|
|
@ -37,8 +37,6 @@ class normalize_fn {
|
|||
case expr_kind::Var: case expr_kind::Constant: case expr_kind::Sort:
|
||||
case expr_kind::Meta: case expr_kind::Local: case expr_kind::Macro:
|
||||
return e;
|
||||
case expr_kind::Let:
|
||||
lean_unreachable(); // LCOV_EXCL_LINE
|
||||
case expr_kind::Lambda: case expr_kind::Pi:
|
||||
return normalize_binding(e);
|
||||
case expr_kind::App:
|
||||
|
|
|
@ -289,7 +289,7 @@ expr mk_resolve_macro(expr const & l, expr const & H1, expr const & H2) {
|
|||
return mk_macro(g_resolve_macro_definition, 3, args);
|
||||
}
|
||||
|
||||
register_macro_deserializer_fn
|
||||
static register_macro_deserializer_fn
|
||||
resolve_macro_des_fn(g_resolve_opcode,
|
||||
[](deserializer &, unsigned num, expr const * args) {
|
||||
if (num != 3)
|
||||
|
|
|
@ -822,7 +822,6 @@ struct unifier_fn {
|
|||
expr mtype = mlocal_type(m);
|
||||
buffer<constraints> alts;
|
||||
lean_assert(!is_var(rhs)); // rhs can't be a free variable (this is an invariant of the approach we are using).
|
||||
lean_assert(!is_let(rhs)); // rhs can't be a let, since the rhs is in whnf.
|
||||
// Add Projections to alts
|
||||
unsigned vidx = margs.size() - 1;
|
||||
for (expr const & marg : margs) {
|
||||
|
|
|
@ -117,8 +117,6 @@ static unsigned count_core(expr const & a, expr_set & s) {
|
|||
return count_core(app_fn(a), s) + count_core(app_arg(a), s) + 1;
|
||||
case expr_kind::Lambda: case expr_kind::Pi:
|
||||
return count_core(binding_domain(a), s) + count_core(binding_body(a), s) + 1;
|
||||
case expr_kind::Let:
|
||||
return count_core(let_value(a), s) + count_core(let_body(a), s) + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -269,7 +267,7 @@ static void tst13() {
|
|||
}
|
||||
|
||||
static void tst14() {
|
||||
expr l = mk_let("a", Bool, Const("b"), Var(0));
|
||||
expr l = Const("b");
|
||||
check_serializer(l);
|
||||
std::cout << l << "\n";
|
||||
lean_assert(closed(l));
|
||||
|
@ -292,11 +290,6 @@ static void tst15() {
|
|||
lean_assert(has_metavar(Pi({a, m}, a)));
|
||||
lean_assert(has_metavar(Fun({a, Type}, m)));
|
||||
lean_assert(has_metavar(Fun({a, m}, a)));
|
||||
lean_assert(!has_metavar(Let(a, Type, Bool, a)));
|
||||
lean_assert(!has_metavar(mk_let(name("a"), Type, f(x), f(f(x)))));
|
||||
lean_assert(has_metavar(mk_let(name("a"), m, f(x), f(f(x)))));
|
||||
lean_assert(has_metavar(mk_let(name("a"), Type, f(m), f(f(x)))));
|
||||
lean_assert(has_metavar(mk_let(name("a"), Type, f(x), f(f(m)))));
|
||||
lean_assert(has_metavar(f(a, a, m)));
|
||||
lean_assert(has_metavar(f(a, m, a, a)));
|
||||
lean_assert(!has_metavar(f(a, a, a, a)));
|
||||
|
@ -317,7 +310,6 @@ static void tst16() {
|
|||
check_copy(mk_metavar("M", Bool));
|
||||
check_copy(mk_lambda("x", a, Var(0)));
|
||||
check_copy(mk_pi("x", a, Var(0)));
|
||||
check_copy(mk_let("x", Bool, a, Var(0)));
|
||||
}
|
||||
|
||||
static void tst17() {
|
||||
|
@ -358,10 +350,6 @@ static void tst18() {
|
|||
lean_assert(has_local(Pi({a, l}, a)));
|
||||
lean_assert(has_local(Fun({a, Type}, l)));
|
||||
lean_assert(has_local(Fun({a, l}, a)));
|
||||
lean_assert(!has_local(Let(a, Type, Bool, a)));
|
||||
lean_assert(has_local(mk_let(name("a"), l, f(x), f(f(x)))));
|
||||
lean_assert(has_local(mk_let(name("a"), Type, f(l), f(f(x)))));
|
||||
lean_assert(has_local(mk_let(name("a"), Type, f(x), f(f(l)))));
|
||||
lean_assert(has_local(f(a, a, l)));
|
||||
lean_assert(has_local(f(a, l, a, a)));
|
||||
lean_assert(!has_local(f(a, a, a, a)));
|
||||
|
|
|
@ -31,18 +31,8 @@ static void tst1() {
|
|||
lean_assert(beta_reduce(F3) == f(a, a));
|
||||
}
|
||||
|
||||
static void tst2() {
|
||||
expr x = Const("x");
|
||||
expr a = Const("a");
|
||||
expr f = Const("f");
|
||||
expr N = Const("N");
|
||||
expr F1 = Let(x, N, a, f(x));
|
||||
lean_assert(head_beta_reduce(F1) == F1);
|
||||
}
|
||||
|
||||
int main() {
|
||||
save_stack_info();
|
||||
tst1();
|
||||
tst2();
|
||||
return has_violations() ? 1 : 0;
|
||||
}
|
||||
|
|
|
@ -25,11 +25,6 @@ static void tst1() {
|
|||
std::cout << F2 << "\n";
|
||||
lean_assert(is_eqp(app_arg(app_fn(F2)), app_arg(F2)));
|
||||
max_fn.clear();
|
||||
F1 = f(Let(x, Type, f(a1), f(x, x)), Let(y, Type, f(a1), f(y, y)));
|
||||
lean_assert(!is_eqp(app_arg(app_fn(F1)), app_arg(F1)));
|
||||
F2 = max_fn(F1);
|
||||
std::cout << F2 << "\n";
|
||||
lean_assert(is_eqp(app_arg(app_fn(F2)), app_arg(F2)));
|
||||
}
|
||||
|
||||
static void tst2() {
|
||||
|
|
|
@ -17,7 +17,7 @@ static void tst1() {
|
|||
expr t = Type;
|
||||
expr z = Const("z");
|
||||
expr m = mk_metavar("a", Type);
|
||||
expr F = mk_let("z", mk_Bool(), Type, mk_pi("y", t, mk_lambda("x", t, f(f(f(x, a), Const("10")), f(x, m)))));
|
||||
expr F = mk_pi("y", t, mk_lambda("x", t, f(f(f(x, a), Const("10")), f(x, m))));
|
||||
expr G = deep_copy(F);
|
||||
lean_assert(F == G);
|
||||
lean_assert(!is_eqp(F, G));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
-- Correct version
|
||||
check let bool : Type.{1} := Type.{0},
|
||||
and (p q : bool) : bool := ∀ c : bool, (p → q → c) → c,
|
||||
infixl `∧` 25 := and,
|
||||
check let bool [inline] := Type.{0},
|
||||
and [inline] (p q : bool) := ∀ c : bool, (p → q → c) → c,
|
||||
infixl `∧` 25 := and,
|
||||
and_intro (p q : bool) (H1 : p) (H2 : q) : p ∧ q
|
||||
:= λ (c : bool) (H : p → q → c), H H1 H2,
|
||||
and_elim_left (p q : bool) (H : p ∧ q) : p
|
||||
|
@ -10,10 +10,10 @@ check let bool : Type.{1} := Type.{0},
|
|||
:= H q (λ (H1 : p) (H2 : q), H2)
|
||||
in and_intro
|
||||
|
||||
check let bool : Type.{1} := Type.{0},
|
||||
and (p q : bool) : bool := ∀ c : bool, (p → q → c) → c,
|
||||
infixl `∧` 25 := and,
|
||||
and_intro (p q : bool) (H1 : p) (H2 : q) : q ∧ p
|
||||
check let bool [inline] := Type.{0},
|
||||
and [inline] (p q : bool) := ∀ c : bool, (p → q → c) → c,
|
||||
infixl `∧` 25 := and,
|
||||
and_intro [fact] (p q : bool) (H1 : p) (H2 : q) : q ∧ p
|
||||
:= λ (c : bool) (H : p → q → c), H H1 H2,
|
||||
and_elim_left (p q : bool) (H : p ∧ q) : p
|
||||
:= H p (λ (H1 : p) (H2 : q), H1),
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
let bool : Type := Bool in (let and : bool -> bool -> bool := fun (p : bool) (q : bool), (Pi (c : bool) (a : p -> q -> c), c) in (let and_intro : Pi (p : bool) (q : bool) (H1 : p) (H2 : q), (and p q) := fun (p : bool) (q : bool) (H1 : p) (H2 : q) (c : bool) (H : p -> q -> c), (H H1 H2) in (let and_elim_left : Pi (p : bool) (q : bool) (H : and p q), p := fun (p : bool) (q : bool) (H : and p q), (H p (fun (H1 : p) (H2 : q), H1)) in (let and_elim_right : Pi (p : bool) (q : bool) (H : and p q), q := fun (p : bool) (q : bool) (H : and p q), (H q (fun (H1 : p) (H2 : q), H2)) in and_intro)))) : Pi (p : Bool) (q : Bool) (H1 : p) (H2 : q) (c : Bool) (H : p -> q -> c), c
|
||||
let1.lean:16:10: error: type mismatch at definition 'and_intro', expected type
|
||||
let and_intro : Pi (p : Bool) (q : Bool) (H1 : p) (H2 : q), ((fun (p : Bool) (q : Bool), (Pi (c : Bool) (a : p -> q -> c), c)) p q) := fun (p : Bool) (q : Bool) (H1 : p) (H2 : q) (c : Bool) (H : p -> q -> c), (H H1 H2) in (let and_elim_left : Pi (p : Bool) (q : Bool) (H : (fun (p : Bool) (q : Bool), (Pi (c : Bool) (a : p -> q -> c), c)) p q), p := fun (p : Bool) (q : Bool) (H : (fun (p : Bool) (q : Bool), (Pi (c : Bool) (a : p -> q -> c), c)) p q), (H p (fun (H1 : p) (H2 : q), H1)) in (let and_elim_right : Pi (p : Bool) (q : Bool) (H : (fun (p : Bool) (q : Bool), (Pi (c : Bool) (a : p -> q -> c), c)) p q), q := fun (p : Bool) (q : Bool) (H : (fun (p : Bool) (q : Bool), (Pi (c : Bool) (a : p -> q -> c), c)) p q), (H q (fun (H1 : p) (H2 : q), H2)) in and_intro)) : Pi (p : Bool) (q : Bool) (H1 : p) (H2 : q), ((fun (p : Bool) (q : Bool), (Pi (c : Bool) (a : p -> q -> c), c)) p q)
|
||||
let1.lean:17:20: error: type mismatch at application
|
||||
(fun (and_intro : Pi (p : Bool) (q : Bool) (H1 : p) (H2 : q), ((fun (p : Bool) (q : Bool), (Pi (c : Bool) (a : p -> q -> c), c)) q p)), (let and_elim_left : Pi (p : Bool) (q : Bool) (H : (fun (p : Bool) (q : Bool), (Pi (c : Bool) (a : p -> q -> c), c)) p q), p := fun (p : Bool) (q : Bool) (H : (fun (p : Bool) (q : Bool), (Pi (c : Bool) (a : p -> q -> c), c)) p q), (H p (fun (H1 : p) (H2 : q), H1)) in (let and_elim_right : Pi (p : Bool) (q : Bool) (H : (fun (p : Bool) (q : Bool), (Pi (c : Bool) (a : p -> q -> c), c)) p q), q := fun (p : Bool) (q : Bool) (H : (fun (p : Bool) (q : Bool), (Pi (c : Bool) (a : p -> q -> c), c)) p q), (H q (fun (H1 : p) (H2 : q), H2)) in and_intro))) (fun (p : Bool) (q : Bool) (H1 : p) (H2 : q) (c : Bool) (H : p -> q -> c), (H H1 H2))
|
||||
expected type:
|
||||
Pi (p : Bool) (q : Bool) (H1 : p) (H2 : q), ((fun (p : Bool) (q : Bool), (Pi (c : Bool) (a : p -> q -> c), c)) q p)
|
||||
given type:
|
||||
Pi (p : Bool) (q : Bool) (H1 : p) (H2 : q) (c : Bool) (H : p -> q -> c), c
|
||||
|
|
|
@ -22,7 +22,6 @@ local l2 = mk_lambda("a", Bool, Var(0), binder_info(true, false))
|
|||
assert(not l1:binding_info():is_implicit())
|
||||
assert(l2:binding_info():is_implicit())
|
||||
|
||||
local let1 = mk_let("a", Bool, Const("true"), f(Var(0)))
|
||||
|
||||
local b = Const("b")
|
||||
local pi3 = Pi({{a, Bool}, {b, Bool}}, a)
|
||||
|
|
|
@ -5,6 +5,4 @@ local T = Const("T")
|
|||
print(Pi({{A, Type}, {a, A}, {A, vec(A)}, {a, A}}, a))
|
||||
local t = mk_pi("A", Type, mk_pi("a", Var(0), mk_pi("A", vec(Var(1)), mk_pi("a", Var(0), T(Var(0), Var(2))))))
|
||||
print(t)
|
||||
print(Let(A, Type, Bool, Pi(a, A, Let(A, Type, A, Pi(a, A, a)))))
|
||||
print(mk_let("A", Type, Bool, mk_pi("a", Var(0), mk_let("A", Type, Var(1), mk_pi("a", Var(0), T(Var(0), Var(1), Var(2)))))))
|
||||
print(mk_let("A", Type, Bool, mk_pi("a", Var(0), mk_let("A", Type, Var(1), mk_pi("a", Var(0), T(Var(0), Var(1), Var(2), Var(3)))))))
|
||||
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
assert(not mk_let("a", Type, Var(0), Var(0)):closed())
|
||||
local env = bare_environment()
|
||||
local A = Const("A")
|
||||
env = add_decl(env, mk_var_decl("A", Type))
|
||||
env = add_decl(env, mk_var_decl("g", mk_arrow(A, mk_arrow(A, A))))
|
||||
env = add_decl(env, mk_var_decl("f", mk_arrow(A, Bool)))
|
||||
env = add_decl(env, mk_var_decl("a", A))
|
||||
local a = Const("a")
|
||||
local b = Const("b")
|
||||
local x = Const("x")
|
||||
local y = Const("y")
|
||||
local g = Const("g")
|
||||
local f = Const("f")
|
||||
local tc = type_checker(env)
|
||||
print(Let(x, A, a, f(x)))
|
||||
print(Let(x, A, a, y, A, f(f(x)), f(x)))
|
||||
assert(Let(x, A, a, y, A, f(f(x)), f(x)) == Let({{x, A, a}, {y, A, f(f(x))}}, f(x)))
|
||||
print(Let({{x, A, a}, {y, A, g(g(x), x, a)}}, f(y)))
|
||||
local t = Let({{x, A, a}, {y, A, g(g(x), x, a)}}, f(y))
|
||||
assert(t:let_name() == name("x"))
|
||||
assert(t:let_type() == A)
|
||||
assert(t:let_value() == a)
|
||||
assert(t:let_body():is_let())
|
||||
print(tc:check(Let({{x, A, a}, {y, A, g(g(x, a), x)}}, f(y))))
|
||||
|
Loading…
Reference in a new issue