Rename normalize context to local_context. Create context. Fix bug in name.cpp
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
3cef072cca
commit
bed5f09907
6 changed files with 188 additions and 103 deletions
27
src/kernel/context.h
Normal file
27
src/kernel/context.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
#include "expr.h"
|
||||
#include "list.h"
|
||||
|
||||
namespace lean {
|
||||
class context_entry {
|
||||
name m_name;
|
||||
expr m_type;
|
||||
expr m_body;
|
||||
public:
|
||||
context_entry(name const & n, expr const & t, expr const & b):m_name(n), m_type(t), m_body(b) {}
|
||||
context_entry(expr const & t, expr const & b):m_type(t), m_body(b) {}
|
||||
explicit context_entry(expr const & t):m_type(t) {}
|
||||
~context_entry() {}
|
||||
name const & get_name() const { return m_name; }
|
||||
expr const & get_type() const { return m_type; }
|
||||
expr const & get_body() const { return m_body; }
|
||||
};
|
||||
typedef list<context_entry> context;
|
||||
context extend(context const & c, context_entry const & e) { return cons(e, c); }
|
||||
}
|
|
@ -6,6 +6,8 @@ Author: Leonardo de Moura
|
|||
*/
|
||||
#include <algorithm>
|
||||
#include "expr.h"
|
||||
#include "context.h"
|
||||
#include "environment.h"
|
||||
#include "free_vars.h"
|
||||
#include "list.h"
|
||||
#include "buffer.h"
|
||||
|
@ -15,18 +17,23 @@ Author: Leonardo de Moura
|
|||
namespace lean {
|
||||
|
||||
class value;
|
||||
typedef list<value> context;
|
||||
typedef list<value> local_context;
|
||||
enum class value_kind { Expr, Closure, BoundedVar };
|
||||
class value {
|
||||
unsigned m_kind:2;
|
||||
unsigned m_bvar:30;
|
||||
expr m_expr;
|
||||
context m_ctx;
|
||||
unsigned m_kind:2;
|
||||
unsigned m_bvar:30;
|
||||
expr m_expr;
|
||||
local_context m_ctx;
|
||||
public:
|
||||
value() {}
|
||||
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)); }
|
||||
value(expr const & e, local_context const & c):
|
||||
m_kind(static_cast<unsigned>(value_kind::Closure)),
|
||||
m_expr(e),
|
||||
m_ctx(c) {
|
||||
lean_assert(is_lambda(e));
|
||||
}
|
||||
|
||||
value_kind kind() const { return static_cast<value_kind>(m_kind); }
|
||||
|
||||
|
@ -34,112 +41,137 @@ public:
|
|||
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; }
|
||||
expr const & get_expr() const { lean_assert(is_expr() || is_closure()); return m_expr; }
|
||||
local_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; }
|
||||
};
|
||||
|
||||
value_kind kind(value const & v) { return v.kind(); }
|
||||
expr const & to_expr(value const & v) { return v.get_expr(); }
|
||||
context const & ctx_of(value const & v) { return v.get_ctx(); }
|
||||
unsigned to_bvar(value const & v) { return v.get_var_idx(); }
|
||||
value_kind kind(value const & v) { return v.kind(); }
|
||||
expr const & to_expr(value const & v) { return v.get_expr(); }
|
||||
local_context const & ctx_of(value const & v) { return v.get_ctx(); }
|
||||
unsigned to_bvar(value const & v) { return v.get_var_idx(); }
|
||||
|
||||
value lookup(context const & c, unsigned i) {
|
||||
context const * curr = &c;
|
||||
while (!is_nil(*curr)) {
|
||||
if (i == 0)
|
||||
return head(*curr);
|
||||
--i;
|
||||
curr = &tail(*curr);
|
||||
}
|
||||
throw exception("unknown free variable");
|
||||
}
|
||||
local_context extend(local_context const & c, value const & v) { return cons(v, c); }
|
||||
|
||||
context extend(context const & c, value const & v) { return cons(v, c); }
|
||||
class normalize_fn {
|
||||
environment const & m_env;
|
||||
context const & m_ctx;
|
||||
|
||||
value normalize(expr const & a, context const & c, unsigned k);
|
||||
expr reify(value const & v, unsigned k);
|
||||
|
||||
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);
|
||||
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); })) {
|
||||
if (n == 2)
|
||||
return lower_free_vars(arg(new_b, 0), 1);
|
||||
else
|
||||
return lower_free_vars(app(n - 1, begin_args(new_b)), 1);
|
||||
value lookup(local_context const & c, unsigned i) {
|
||||
local_context const * it1 = &c;
|
||||
while (!is_nil(*it1)) {
|
||||
if (i == 0)
|
||||
return head(*it1);
|
||||
--i;
|
||||
it1 = &tail(*it1);
|
||||
}
|
||||
return lambda(abst_name(a), new_t, new_b);
|
||||
}
|
||||
else {
|
||||
return lambda(abst_name(a), new_t, new_b);
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
value normalize(expr const & a, context const & c, unsigned k) {
|
||||
lean_trace("normalize", tout << "Normalize, k: " << k << "\n" << a << "\n";);
|
||||
switch (a.kind()) {
|
||||
case expr_kind::Var:
|
||||
return lookup(c, var_idx(a));
|
||||
case expr_kind::Constant: case expr_kind::Type: case expr_kind::Numeral:
|
||||
return value(a);
|
||||
case expr_kind::App: {
|
||||
value f = normalize(arg(a, 0), c, k);
|
||||
unsigned i = 1;
|
||||
unsigned n = num_args(a);
|
||||
while (true) {
|
||||
if (f.is_closure()) {
|
||||
// beta reduction
|
||||
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);
|
||||
if (i == n - 1)
|
||||
return f;
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
// TODO: support for interpreted symbols
|
||||
buffer<expr> new_args;
|
||||
new_args.push_back(reify(f, k));
|
||||
for (; i < n; i++)
|
||||
new_args.push_back(reify(normalize(arg(a, i), c, k), k));
|
||||
return value(app(new_args.size(), new_args.data()));
|
||||
context const * it2 = &m_ctx;
|
||||
while (!is_nil(*it2)) {
|
||||
if (i == 0) {
|
||||
expr const & b = head(*it2).get_body();
|
||||
if (!is_null(b))
|
||||
return value(b);
|
||||
else break;
|
||||
}
|
||||
--i;
|
||||
it2 = &tail(*it2);
|
||||
}
|
||||
throw exception("unknown free variable");
|
||||
}
|
||||
case expr_kind::Lambda:
|
||||
return value(a, c);
|
||||
case expr_kind::Pi: {
|
||||
|
||||
expr reify_closure(expr const & a, local_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);
|
||||
return value(pi(abst_name(a), new_t, new_b));
|
||||
}}
|
||||
lean_unreachable();
|
||||
return value(a);
|
||||
if (is_app(new_b)) {
|
||||
// (lambda (x:T) (app f ... (var 0)))
|
||||
// check eta-rule applicability
|
||||
unsigned n = num_args(new_b);
|
||||
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); })) {
|
||||
if (n == 2)
|
||||
return lower_free_vars(arg(new_b, 0), 1);
|
||||
else
|
||||
return lower_free_vars(app(n - 1, begin_args(new_b)), 1);
|
||||
}
|
||||
return lambda(abst_name(a), new_t, new_b);
|
||||
}
|
||||
else {
|
||||
return lambda(abst_name(a), new_t, new_b);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
value normalize(expr const & a, local_context const & c, unsigned k) {
|
||||
lean_trace("normalize", tout << "Normalize, k: " << k << "\n" << a << "\n";);
|
||||
switch (a.kind()) {
|
||||
case expr_kind::Var:
|
||||
return lookup(c, var_idx(a));
|
||||
case expr_kind::Constant: case expr_kind::Type: case expr_kind::Numeral:
|
||||
return value(a);
|
||||
case expr_kind::App: {
|
||||
value f = normalize(arg(a, 0), c, k);
|
||||
unsigned i = 1;
|
||||
unsigned n = num_args(a);
|
||||
while (true) {
|
||||
if (f.is_closure()) {
|
||||
// beta reduction
|
||||
expr const & fv = to_expr(f);
|
||||
lean_trace("normalize", tout << "beta reduction...\n" << fv << "\n";);
|
||||
local_context new_c = extend(ctx_of(f), normalize(arg(a, i), c, k));
|
||||
f = normalize(abst_body(fv), new_c, k);
|
||||
if (i == n - 1)
|
||||
return f;
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
// TODO: support for interpreted symbols
|
||||
buffer<expr> new_args;
|
||||
new_args.push_back(reify(f, k));
|
||||
for (; i < n; i++)
|
||||
new_args.push_back(reify(normalize(arg(a, i), c, k), k));
|
||||
return value(app(new_args.size(), new_args.data()));
|
||||
}
|
||||
}
|
||||
}
|
||||
case expr_kind::Lambda:
|
||||
return value(a, c);
|
||||
case expr_kind::Pi: {
|
||||
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);
|
||||
return value(pi(abst_name(a), new_t, new_b));
|
||||
}}
|
||||
lean_unreachable();
|
||||
return value(a);
|
||||
}
|
||||
|
||||
public:
|
||||
normalize_fn(environment const & env, context const & ctx):
|
||||
m_env(env),
|
||||
m_ctx(ctx) {
|
||||
}
|
||||
|
||||
expr operator()(expr const & e) {
|
||||
return reify(normalize(e, local_context(), 0), 0);
|
||||
}
|
||||
};
|
||||
|
||||
expr normalize(expr const & e, environment const & env, context const & ctx) {
|
||||
return normalize_fn(env, ctx)(e);
|
||||
}
|
||||
|
||||
expr normalize(expr const & e) {
|
||||
return reify(normalize(e, context(), 0), 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,10 @@ Author: Leonardo de Moura
|
|||
*/
|
||||
#pragma once
|
||||
#include "expr.h"
|
||||
#include "environment.h"
|
||||
#include "context.h"
|
||||
|
||||
namespace lean {
|
||||
expr normalize(expr const & e);
|
||||
class environment;
|
||||
expr normalize(expr const & e, environment const & env, context const & ctx = context());
|
||||
}
|
||||
|
|
|
@ -11,6 +11,11 @@ Author: Leonardo de Moura
|
|||
#include "sets.h"
|
||||
using namespace lean;
|
||||
|
||||
expr normalize(expr const & e) {
|
||||
environment env;
|
||||
return normalize(e, env);
|
||||
}
|
||||
|
||||
static void eval(expr const & e) { std::cout << e << " --> " << normalize(e) << "\n"; }
|
||||
static expr t() { return constant("t"); }
|
||||
static expr lam(expr const & e) { return lambda("_", t(), e); }
|
||||
|
@ -118,9 +123,21 @@ static void tst1() {
|
|||
lean_assert(normalize(lam(l12(l01))) == lam(lam(v(1)(v(1)))));
|
||||
}
|
||||
|
||||
static void tst2() {
|
||||
environment env;
|
||||
expr f = constant("f");
|
||||
expr a = constant("a");
|
||||
expr b = constant("b");
|
||||
expr x = var(0);
|
||||
expr y = var(1);
|
||||
expr t = type(level());
|
||||
std::cout << normalize(f(x,x), env, extend(context(), context_entry(t, f(a)))) << "\n";
|
||||
}
|
||||
|
||||
int main() {
|
||||
continue_on_violation(true);
|
||||
tst1();
|
||||
tst_church_numbers();
|
||||
tst1();
|
||||
tst2();
|
||||
return has_violations() ? 1 : 0;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,11 @@ Author: Leonardo de Moura
|
|||
#include "test.h"
|
||||
using namespace lean;
|
||||
|
||||
expr normalize(expr const & e) {
|
||||
environment env;
|
||||
return normalize(e, env);
|
||||
}
|
||||
|
||||
static void mk(expr const & a) {
|
||||
expr b = constant("b");
|
||||
for (unsigned i = 0; i < 100; i++) {
|
||||
|
|
|
@ -115,7 +115,8 @@ name::name(unsigned k):name(name(), k) {
|
|||
}
|
||||
|
||||
name::name(name const & other):m_ptr(other.m_ptr) {
|
||||
m_ptr->inc_ref();
|
||||
if (m_ptr)
|
||||
m_ptr->inc_ref();
|
||||
}
|
||||
|
||||
name::name(name && other):m_ptr(other.m_ptr) {
|
||||
|
|
Loading…
Reference in a new issue