2013-07-25 02:36:54 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
|
|
|
#include <algorithm>
|
|
|
|
#include "expr.h"
|
2013-07-26 19:37:13 +00:00
|
|
|
#include "free_vars.h"
|
2013-07-25 02:36:54 +00:00
|
|
|
#include "list.h"
|
|
|
|
#include "buffer.h"
|
|
|
|
#include "trace.h"
|
2013-07-26 02:13:45 +00:00
|
|
|
#include "exception.h"
|
2013-07-25 02:36:54 +00:00
|
|
|
|
|
|
|
namespace lean {
|
|
|
|
|
|
|
|
class value;
|
|
|
|
typedef list<value> context;
|
2013-07-26 02:13:45 +00:00
|
|
|
enum class value_kind { Expr, Closure, BoundedVar };
|
2013-07-25 02:36:54 +00:00
|
|
|
class value {
|
2013-07-26 02:13:45 +00:00
|
|
|
unsigned m_kind:2;
|
|
|
|
unsigned m_bvar:30;
|
|
|
|
expr m_expr;
|
|
|
|
context m_ctx;
|
2013-07-25 02:36:54 +00:00
|
|
|
public:
|
|
|
|
value() {}
|
2013-07-26 02:13:45 +00:00
|
|
|
explicit value(expr const & e):m_kind(static_cast<unsigned>(value_kind::Expr)), m_expr(e) {}
|
|
|
|
explicit value(unsigned k):m_kind(static_cast<unsigned>(value_kind::BoundedVar)), m_bvar(k) {}
|
|
|
|
value(expr const & e, context const & c):m_kind(static_cast<unsigned>(value_kind::Closure)), m_expr(e), m_ctx(c) { lean_assert(is_lambda(e)); }
|
2013-07-25 02:36:54 +00:00
|
|
|
|
2013-07-26 02:13:45 +00:00
|
|
|
value_kind kind() const { return static_cast<value_kind>(m_kind); }
|
|
|
|
|
|
|
|
bool is_expr() const { return kind() == value_kind::Expr; }
|
|
|
|
bool is_closure() const { return kind() == value_kind::Closure; }
|
|
|
|
bool is_bounded_var() const { return kind() == value_kind::BoundedVar; }
|
|
|
|
|
|
|
|
expr const & get_expr() const { lean_assert(is_expr() || is_closure()); return m_expr; }
|
|
|
|
context const & get_ctx() const { lean_assert(is_closure()); return m_ctx; }
|
|
|
|
unsigned get_var_idx() const { lean_assert(is_bounded_var()); return m_bvar; }
|
2013-07-25 02:36:54 +00:00
|
|
|
};
|
|
|
|
|
2013-07-26 02:13:45 +00:00
|
|
|
value_kind kind(value const & v) { return v.kind(); }
|
2013-07-25 02:36:54 +00:00
|
|
|
expr const & to_expr(value const & v) { return v.get_expr(); }
|
2013-07-26 02:13:45 +00:00
|
|
|
context const & ctx_of(value const & v) { return v.get_ctx(); }
|
|
|
|
unsigned to_bvar(value const & v) { return v.get_var_idx(); }
|
2013-07-25 02:36:54 +00:00
|
|
|
|
2013-07-26 02:13:45 +00:00
|
|
|
value lookup(context const & c, unsigned i) {
|
2013-07-25 02:36:54 +00:00
|
|
|
context const * curr = &c;
|
|
|
|
while (!is_nil(*curr)) {
|
2013-07-26 02:13:45 +00:00
|
|
|
if (i == 0)
|
|
|
|
return head(*curr);
|
2013-07-25 02:36:54 +00:00
|
|
|
--i;
|
|
|
|
curr = &tail(*curr);
|
|
|
|
}
|
2013-07-26 02:13:45 +00:00
|
|
|
throw exception("unknown free variable");
|
2013-07-25 02:36:54 +00:00
|
|
|
}
|
|
|
|
|
2013-07-26 02:13:45 +00:00
|
|
|
context extend(context const & c, value const & v) { return cons(v, c); }
|
2013-07-25 02:36:54 +00:00
|
|
|
|
2013-07-26 02:13:45 +00:00
|
|
|
value normalize(expr const & a, context const & c, unsigned k);
|
|
|
|
expr reify(value const & v, unsigned k);
|
2013-07-25 02:36:54 +00:00
|
|
|
|
2013-07-26 02:13:45 +00:00
|
|
|
expr reify_closure(expr const & a, context const & c, unsigned k) {
|
|
|
|
lean_assert(is_lambda(a));
|
|
|
|
expr new_t = reify(normalize(abst_type(a), c, k), k);
|
|
|
|
expr new_b = reify(normalize(abst_body(a), extend(c, value(k)), k+1), k+1);
|
|
|
|
// TODO: ETA-reduction
|
|
|
|
if (is_app(new_b)) {
|
|
|
|
// (lambda (x:T) (app f ... (var 0)))
|
|
|
|
// check eta-rule applicability
|
|
|
|
unsigned n = num_args(new_b);
|
2013-07-26 19:37:13 +00:00
|
|
|
if (is_var(arg(new_b, n - 1), 0) &&
|
|
|
|
std::all_of(begin_args(new_b),
|
|
|
|
end_args(new_b) - 1,
|
|
|
|
[](expr const & arg) { return !has_free_var(arg, 0); })) {
|
2013-07-26 02:13:45 +00:00
|
|
|
if (n == 2)
|
2013-07-26 19:37:13 +00:00
|
|
|
return lower_free_vars(arg(new_b, 0), 1);
|
2013-07-26 02:13:45 +00:00
|
|
|
else
|
2013-07-26 19:37:13 +00:00
|
|
|
return lower_free_vars(app(n - 1, begin_args(new_b)), 1);
|
2013-07-25 02:36:54 +00:00
|
|
|
}
|
|
|
|
return lambda(abst_name(a), new_t, new_b);
|
|
|
|
}
|
|
|
|
else {
|
2013-07-26 02:13:45 +00:00
|
|
|
return lambda(abst_name(a), new_t, new_b);
|
2013-07-25 02:36:54 +00:00
|
|
|
}
|
|
|
|
}
|
2013-07-26 02:13:45 +00:00
|
|
|
expr reify(value const & v, unsigned k) {
|
|
|
|
lean_trace("normalize", tout << "Reify kind: " << static_cast<unsigned>(v.kind()) << "\n";
|
|
|
|
if (v.is_bounded_var()) tout << "#" << to_bvar(v); else tout << to_expr(v); tout << "\n";);
|
|
|
|
switch (v.kind()) {
|
|
|
|
case value_kind::Expr: return to_expr(v);
|
|
|
|
case value_kind::BoundedVar: return var(k - to_bvar(v) - 1);
|
|
|
|
case value_kind::Closure: return reify_closure(to_expr(v), ctx_of(v), k);
|
|
|
|
}
|
|
|
|
lean_unreachable();
|
|
|
|
return expr();
|
2013-07-25 02:36:54 +00:00
|
|
|
}
|
|
|
|
|
2013-07-26 02:13:45 +00:00
|
|
|
value normalize(expr const & a, context const & c, unsigned k) {
|
|
|
|
lean_trace("normalize", tout << "Normalize, k: " << k << "\n" << a << "\n";);
|
2013-07-25 02:36:54 +00:00
|
|
|
switch (a.kind()) {
|
2013-07-26 02:13:45 +00:00
|
|
|
case expr_kind::Var:
|
|
|
|
return lookup(c, var_idx(a));
|
2013-07-25 02:36:54 +00:00
|
|
|
case expr_kind::Constant: case expr_kind::Prop: case expr_kind::Type: case expr_kind::Numeral:
|
|
|
|
return value(a);
|
|
|
|
case expr_kind::App: {
|
2013-07-26 02:13:45 +00:00
|
|
|
value f = normalize(arg(a, 0), c, k);
|
2013-07-25 02:36:54 +00:00
|
|
|
unsigned i = 1;
|
|
|
|
unsigned n = num_args(a);
|
|
|
|
while (true) {
|
2013-07-26 02:13:45 +00:00
|
|
|
if (f.is_closure()) {
|
2013-07-25 02:36:54 +00:00
|
|
|
// beta reduction
|
2013-07-26 02:13:45 +00:00
|
|
|
expr const & fv = to_expr(f);
|
|
|
|
lean_trace("normalize", tout << "beta reduction...\n" << fv << "\n";);
|
|
|
|
context new_c = extend(ctx_of(f), normalize(arg(a, i), c, k));
|
|
|
|
f = normalize(abst_body(fv), new_c, k);
|
2013-07-25 02:36:54 +00:00
|
|
|
if (i == n - 1)
|
|
|
|
return f;
|
|
|
|
i++;
|
|
|
|
}
|
2013-07-26 02:13:45 +00:00
|
|
|
else {
|
2013-07-25 02:36:54 +00:00
|
|
|
// TODO: support for interpreted symbols
|
|
|
|
buffer<expr> new_args;
|
2013-07-26 02:13:45 +00:00
|
|
|
new_args.push_back(reify(f, k));
|
2013-07-25 02:36:54 +00:00
|
|
|
for (; i < n; i++)
|
2013-07-26 02:13:45 +00:00
|
|
|
new_args.push_back(reify(normalize(arg(a, i), c, k), k));
|
2013-07-25 02:36:54 +00:00
|
|
|
return value(app(new_args.size(), new_args.data()));
|
2013-07-26 02:13:45 +00:00
|
|
|
}
|
2013-07-25 02:36:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case expr_kind::Lambda:
|
|
|
|
return value(a, c);
|
|
|
|
case expr_kind::Pi: {
|
2013-07-26 02:13:45 +00:00
|
|
|
expr new_t = reify(normalize(abst_type(a), c, k), k);
|
|
|
|
expr new_b = reify(normalize(abst_body(a), extend(c, value(k)), k+1), k+1);
|
2013-07-25 02:36:54 +00:00
|
|
|
return value(pi(abst_name(a), new_t, new_b));
|
|
|
|
}}
|
2013-07-26 02:13:45 +00:00
|
|
|
lean_unreachable();
|
2013-07-25 02:36:54 +00:00
|
|
|
return value(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
expr normalize(expr const & e) {
|
2013-07-26 02:13:45 +00:00
|
|
|
return reify(normalize(e, context(), 0), 0);
|
2013-07-25 02:36:54 +00:00
|
|
|
}
|
|
|
|
}
|