refactor(util/lazy_list): 'lazier' lazy_lists
In the new implementation, even the head of the lazy list is computed on demand. Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
9eb6da2a31
commit
f19944cf09
8 changed files with 236 additions and 170 deletions
|
@ -6,6 +6,7 @@ Author: Leonardo de Moura
|
||||||
*/
|
*/
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include "util/sstream.h"
|
||||||
#include "util/interrupt.h"
|
#include "util/interrupt.h"
|
||||||
#include "util/lazy_list_fn.h"
|
#include "util/lazy_list_fn.h"
|
||||||
#include "library/tactic/tactic_exception.h"
|
#include "library/tactic/tactic_exception.h"
|
||||||
|
@ -22,9 +23,10 @@ tactic & tactic::operator=(tactic && s) {
|
||||||
|
|
||||||
expr tactic::solve(environment const & env, io_state const & io, proof_state const & s) {
|
expr tactic::solve(environment const & env, io_state const & io, proof_state const & s) {
|
||||||
proof_state_seq r = operator()(env, io, s);
|
proof_state_seq r = operator()(env, io, s);
|
||||||
if (!r)
|
auto p = r.pull();
|
||||||
|
if (!p)
|
||||||
throw exception("tactic failed to solve input");
|
throw exception("tactic failed to solve input");
|
||||||
proof_state final = head(r);
|
proof_state final = p->first;
|
||||||
assignment a(final.get_menv());
|
assignment a(final.get_menv());
|
||||||
proof_map m;
|
proof_map m;
|
||||||
return final.get_proof_builder()(m, env, a);
|
return final.get_proof_builder()(m, env, a);
|
||||||
|
@ -37,7 +39,7 @@ expr tactic::solve(environment const & env, io_state const & io, context const &
|
||||||
|
|
||||||
tactic id_tactic() {
|
tactic id_tactic() {
|
||||||
return mk_tactic([](environment const &, io_state const &, proof_state const & s) -> proof_state_seq {
|
return mk_tactic([](environment const &, io_state const &, proof_state const & s) -> proof_state_seq {
|
||||||
return proof_state_seq(s);
|
return to_proof_state_seq(s);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,10 +54,28 @@ tactic now_tactic() {
|
||||||
if (!empty(s.get_goals()))
|
if (!empty(s.get_goals()))
|
||||||
return proof_state_seq();
|
return proof_state_seq();
|
||||||
else
|
else
|
||||||
return proof_state_seq(s);
|
return to_proof_state_seq(s);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tactic trace_tactic(std::string const & msg) {
|
||||||
|
return mk_tactic([=](environment const &, io_state const & io, proof_state const & s) -> proof_state_seq {
|
||||||
|
return proof_state_seq([=]() {
|
||||||
|
io.get_diagnostic_channel() << msg << "\n";
|
||||||
|
io.get_diagnostic_channel().get_stream().flush();
|
||||||
|
return some(mk_pair(s, proof_state_seq()));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tactic trace_tactic(sstream const & msg) {
|
||||||
|
return trace_tactic(msg.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
tactic trace_tactic(char const * msg) {
|
||||||
|
return trace_tactic(std::string(msg));
|
||||||
|
}
|
||||||
|
|
||||||
tactic assumption_tactic() {
|
tactic assumption_tactic() {
|
||||||
return mk_tactic([](environment const &, io_state const &, proof_state const & s) -> proof_state_seq {
|
return mk_tactic([](environment const &, io_state const &, proof_state const & s) -> proof_state_seq {
|
||||||
list<std::pair<name, expr>> proofs;
|
list<std::pair<name, expr>> proofs;
|
||||||
|
@ -84,7 +104,7 @@ tactic assumption_tactic() {
|
||||||
}
|
}
|
||||||
return p(new_m, env, a);
|
return p(new_m, env, a);
|
||||||
});
|
});
|
||||||
return proof_state_seq(proof_state(s, new_goals, new_p));
|
return to_proof_state_seq(proof_state(s, new_goals, new_p));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,14 +122,8 @@ tactic then(tactic t1, tactic t2) {
|
||||||
tactic orelse(tactic t1, tactic t2) {
|
tactic orelse(tactic t1, tactic t2) {
|
||||||
return mk_tactic([=](environment const & env, io_state const & io, proof_state const & s) -> proof_state_seq {
|
return mk_tactic([=](environment const & env, io_state const & io, proof_state const & s) -> proof_state_seq {
|
||||||
tactic _t1(t1);
|
tactic _t1(t1);
|
||||||
proof_state_seq r = _t1(env, io, s);
|
|
||||||
if (r) {
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
check_interrupted();
|
|
||||||
tactic _t2(t2);
|
tactic _t2(t2);
|
||||||
return _t2(env, io, s);
|
return orelse(_t1(env, io, s), _t2(env, io, s));
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,10 +214,7 @@ tactic par(tactic t1, tactic t2, unsigned check_ms) {
|
||||||
th2.request_interrupt();
|
th2.request_interrupt();
|
||||||
th1.join();
|
th1.join();
|
||||||
th2.join();
|
th2.join();
|
||||||
if (r1)
|
return orelse(r1, r2);
|
||||||
return r1;
|
|
||||||
else
|
|
||||||
return r2;
|
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
th1.request_interrupt();
|
th1.request_interrupt();
|
||||||
th2.request_interrupt();
|
th2.request_interrupt();
|
||||||
|
@ -218,10 +229,11 @@ tactic repeat(tactic t) {
|
||||||
return mk_tactic([=](environment const & env, io_state const & io, proof_state const & s1) -> proof_state_seq {
|
return mk_tactic([=](environment const & env, io_state const & io, proof_state const & s1) -> proof_state_seq {
|
||||||
tactic t1(t);
|
tactic t1(t);
|
||||||
proof_state_seq r = t1(env, io, s1);
|
proof_state_seq r = t1(env, io, s1);
|
||||||
if (!r) {
|
auto p = r.pull();
|
||||||
return proof_state_seq(s1);
|
if (!p) {
|
||||||
|
return to_proof_state_seq(s1);
|
||||||
} else {
|
} else {
|
||||||
return map_append(r, [=](proof_state const & s2) {
|
return map_append(to_proof_state_seq(p), [=](proof_state const & s2) {
|
||||||
check_interrupted();
|
check_interrupted();
|
||||||
tactic t2 = repeat(t1);
|
tactic t2 = repeat(t1);
|
||||||
return t2(env, io, s2);
|
return t2(env, io, s2);
|
||||||
|
@ -233,13 +245,14 @@ tactic repeat(tactic t) {
|
||||||
tactic repeat_at_most(tactic t, unsigned k) {
|
tactic repeat_at_most(tactic t, unsigned k) {
|
||||||
return mk_tactic([=](environment const & env, io_state const & io, proof_state const & s1) -> proof_state_seq {
|
return mk_tactic([=](environment const & env, io_state const & io, proof_state const & s1) -> proof_state_seq {
|
||||||
if (k == 0)
|
if (k == 0)
|
||||||
return proof_state_seq(s1);
|
return to_proof_state_seq(s1);
|
||||||
tactic t1(t);
|
tactic t1(t);
|
||||||
proof_state_seq r = t1(env, io, s1);
|
proof_state_seq r = t1(env, io, s1);
|
||||||
if (!r) {
|
auto p = r.pull();
|
||||||
return proof_state_seq(s1);
|
if (!p) {
|
||||||
|
return to_proof_state_seq(s1);
|
||||||
} else {
|
} else {
|
||||||
return map_append(r, [=](proof_state const & s2) {
|
return map_append(to_proof_state_seq(p), [=](proof_state const & s2) {
|
||||||
check_interrupted();
|
check_interrupted();
|
||||||
tactic t2 = repeat_at_most(t1, k - 1);
|
tactic t2 = repeat_at_most(t1, k - 1);
|
||||||
return t2(env, io, s2);
|
return t2(env, io, s2);
|
||||||
|
@ -260,10 +273,10 @@ tactic force(tactic t) {
|
||||||
tactic _t(t);
|
tactic _t(t);
|
||||||
proof_state_seq r = _t(env, io, s);
|
proof_state_seq r = _t(env, io, s);
|
||||||
buffer<proof_state> buf;
|
buffer<proof_state> buf;
|
||||||
for (auto s2 : r) {
|
for_each(r, [&](proof_state const & s2) {
|
||||||
buf.push_back(s2);
|
buf.push_back(s2);
|
||||||
check_interrupted();
|
check_interrupted();
|
||||||
}
|
});
|
||||||
return to_lazy(to_list(buf.begin(), buf.end()));
|
return to_lazy(to_list(buf.begin(), buf.end()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ Author: Leonardo de Moura
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
#include "util/lazy_list.h"
|
#include "util/lazy_list.h"
|
||||||
#include "library/io_state.h"
|
#include "library/io_state.h"
|
||||||
#include "library/tactic/proof_state.h"
|
#include "library/tactic/proof_state.h"
|
||||||
|
@ -64,6 +65,19 @@ public:
|
||||||
template<typename F>
|
template<typename F>
|
||||||
tactic mk_tactic(F && f) { return tactic(new simple_tactic_cell<F>(std::forward<F>(f))); }
|
tactic mk_tactic(F && f) { return tactic(new simple_tactic_cell<F>(std::forward<F>(f))); }
|
||||||
|
|
||||||
|
inline proof_state_seq to_proof_state_seq(proof_state const & s) {
|
||||||
|
return proof_state_seq([=]() { return some(mk_pair(s, proof_state_seq())); });
|
||||||
|
}
|
||||||
|
|
||||||
|
inline proof_state_seq to_proof_state_seq(proof_state_seq::maybe_pair const & p) {
|
||||||
|
lean_assert(p);
|
||||||
|
return proof_state_seq([=]() { return some(mk_pair(p->first, p->second)); });
|
||||||
|
}
|
||||||
|
|
||||||
|
inline proof_state_seq to_proof_state_seq(proof_state const & s, proof_state_seq const & t) {
|
||||||
|
return proof_state_seq([=]() { return some(mk_pair(s, t)); });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Return a "do nothing" tactic (aka skip).
|
\brief Return a "do nothing" tactic (aka skip).
|
||||||
*/
|
*/
|
||||||
|
@ -80,15 +94,25 @@ tactic now_tactic();
|
||||||
\brief Return a tactic that solves any goal of the form <tt>..., H : A, ... |- A</tt>.
|
\brief Return a tactic that solves any goal of the form <tt>..., H : A, ... |- A</tt>.
|
||||||
*/
|
*/
|
||||||
tactic assumption_tactic();
|
tactic assumption_tactic();
|
||||||
|
/**
|
||||||
|
\brief Return a tactic that just returns the input state, and display the given message in the diagnostic channel.
|
||||||
|
*/
|
||||||
|
tactic trace_tactic(char const * msg);
|
||||||
|
class sstream;
|
||||||
|
tactic trace_tactic(sstream const & msg);
|
||||||
|
tactic trace_tactic(std::string const & msg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Return a tactic that performs \c t1 followed by \c t2.
|
\brief Return a tactic that performs \c t1 followed by \c t2.
|
||||||
*/
|
*/
|
||||||
tactic then(tactic t1, tactic t2);
|
tactic then(tactic t1, tactic t2);
|
||||||
|
inline tactic operator<<(tactic t1, tactic t2) { return then(t1, t2); }
|
||||||
/**
|
/**
|
||||||
\brief Return a tactic that applies \c t1, and if \c t1 returns the empty sequence of states,
|
\brief Return a tactic that applies \c t1, and if \c t1 returns the empty sequence of states,
|
||||||
then applies \c t2.
|
then applies \c t2.
|
||||||
*/
|
*/
|
||||||
tactic orelse(tactic t1, tactic t2);
|
tactic orelse(tactic t1, tactic t2);
|
||||||
|
inline tactic operator||(tactic t1, tactic t2) { return orelse(t1, t2); }
|
||||||
/**
|
/**
|
||||||
\brief Return a tactic that tries the tactic \c t for at most \c ms milliseconds.
|
\brief Return a tactic that tries the tactic \c t for at most \c ms milliseconds.
|
||||||
If the tactic does not terminate in \c ms milliseconds, then the empty
|
If the tactic does not terminate in \c ms milliseconds, then the empty
|
||||||
|
@ -106,6 +130,7 @@ tactic try_for(tactic t, unsigned ms, unsigned check_ms = 1);
|
||||||
from tactic \c t2.
|
from tactic \c t2.
|
||||||
*/
|
*/
|
||||||
tactic append(tactic t1, tactic t2);
|
tactic append(tactic t1, tactic t2);
|
||||||
|
inline tactic operator+(tactic t1, tactic t2) { return append(t1, t2); }
|
||||||
/**
|
/**
|
||||||
\brief Execute both tactics and and combines their results.
|
\brief Execute both tactics and and combines their results.
|
||||||
The results produced by tactics \c t1 and \c t2 are interleaved
|
The results produced by tactics \c t1 and \c t2 are interleaved
|
||||||
|
|
|
@ -25,17 +25,10 @@ tactic loop_tactic() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
tactic msg_tactic(std::string msg) {
|
|
||||||
return mk_tactic([=](environment const &, io_state const &, proof_state const & s) -> proof_state_seq {
|
|
||||||
std::cout << msg << "\n";
|
|
||||||
return proof_state_seq(s);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
tactic set_tactic(std::atomic<bool> * flag) {
|
tactic set_tactic(std::atomic<bool> * flag) {
|
||||||
return mk_tactic([=](environment const &, io_state const &, proof_state const & s) -> proof_state_seq {
|
return mk_tactic([=](environment const &, io_state const &, proof_state const & s) -> proof_state_seq {
|
||||||
*flag = true;
|
*flag = true;
|
||||||
return proof_state_seq(s);
|
return to_proof_state_seq(s);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +64,7 @@ static void tst1() {
|
||||||
check_failure(try_for(loop_tactic(), 100), env, io, ctx, q);
|
check_failure(try_for(loop_tactic(), 100), env, io, ctx, q);
|
||||||
std::cout << "proof 1: " << try_for(t, 10000).solve(env, io, s) << "\n";
|
std::cout << "proof 1: " << try_for(t, 10000).solve(env, io, s) << "\n";
|
||||||
check_failure(try_for(orelse(try_for(loop_tactic(), 10000),
|
check_failure(try_for(orelse(try_for(loop_tactic(), 10000),
|
||||||
msg_tactic(std::string("hello world"))),
|
trace_tactic(std::string("hello world"))),
|
||||||
100),
|
100),
|
||||||
env, io, ctx, q);
|
env, io, ctx, q);
|
||||||
std::atomic<bool> flag1(false);
|
std::atomic<bool> flag1(false);
|
||||||
|
@ -87,10 +80,16 @@ static void tst1() {
|
||||||
std::cout << "proof 2: " << par(loop_tactic(), par(loop_tactic(), t)).solve(env, io, ctx, q) << "\n";
|
std::cout << "proof 2: " << par(loop_tactic(), par(loop_tactic(), t)).solve(env, io, ctx, q) << "\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::cout << "proof 2: " << orelse(then(repeat_at_most(append(msg_tactic("hello1"), msg_tactic("hello2")), 5), fail_tactic()),
|
std::cout << "proof 2: " << orelse(then(repeat_at_most(append(trace_tactic("hello1"), trace_tactic("hello2")), 5), fail_tactic()),
|
||||||
t).solve(env, io, ctx, q) << "\n";
|
t).solve(env, io, ctx, q) << "\n";
|
||||||
std::cout << "------------------\n";
|
std::cout << "------------------\n";
|
||||||
std::cout << "proof 2: " << force(take(then(repeat_at_most(interleave(id_tactic(), id_tactic()), 100), then(msg_tactic("foo"), t)), 5)).solve(env, io, ctx, q) << "\n";
|
std::cout << "proof 2: " << ((trace_tactic("hello1.1") + trace_tactic("hello1.2") + trace_tactic("hello1.3") + trace_tactic("hello1.4")) <<
|
||||||
|
(trace_tactic("hello2.1") + trace_tactic("hello2.2")) <<
|
||||||
|
(trace_tactic("hello3.1") || trace_tactic("hello3.2")) <<
|
||||||
|
assumption_tactic()).solve(env, io, ctx, q) << "\n";
|
||||||
|
std::cout << "------------------\n";
|
||||||
|
std::cout << "proof 2: " << force(take(repeat_at_most(interleave(id_tactic(), id_tactic()), 100) << trace_tactic("foo") << t,
|
||||||
|
5)).solve(env, io, ctx, q) << "\n";
|
||||||
std::cout << "done\n";
|
std::cout << "done\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,3 +61,6 @@ add_test(safe_arith ${CMAKE_CURRENT_BINARY_DIR}/safe_arith)
|
||||||
add_executable(set set.cpp)
|
add_executable(set set.cpp)
|
||||||
target_link_libraries(set ${EXTRA_LIBS})
|
target_link_libraries(set ${EXTRA_LIBS})
|
||||||
add_test(set ${CMAKE_CURRENT_BINARY_DIR}/set)
|
add_test(set ${CMAKE_CURRENT_BINARY_DIR}/set)
|
||||||
|
add_executable(optional optional.cpp)
|
||||||
|
target_link_libraries(optional ${EXTRA_LIBS})
|
||||||
|
add_test(optional ${CMAKE_CURRENT_BINARY_DIR}/optional)
|
||||||
|
|
|
@ -7,6 +7,7 @@ Author: Leonardo de Moura
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "util/test.h"
|
#include "util/test.h"
|
||||||
|
#include "util/optional.h"
|
||||||
#include "util/numerics/mpz.h"
|
#include "util/numerics/mpz.h"
|
||||||
#include "util/pair.h"
|
#include "util/pair.h"
|
||||||
#include "util/lazy_list.h"
|
#include "util/lazy_list.h"
|
||||||
|
@ -15,18 +16,18 @@ Author: Leonardo de Moura
|
||||||
using namespace lean;
|
using namespace lean;
|
||||||
|
|
||||||
lazy_list<int> seq(int s) {
|
lazy_list<int> seq(int s) {
|
||||||
return lazy_list<int>(s, [=]() { return seq(s + 1); });
|
return lazy_list<int>([=]() { return some(mk_pair(s, seq(s + 1))); });
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_list<int> from(int begin, int step, int end) {
|
lazy_list<int> from(int begin, int step, int end) {
|
||||||
if (begin > end)
|
if (begin > end)
|
||||||
return lazy_list<int>();
|
return lazy_list<int>();
|
||||||
else
|
else
|
||||||
return lazy_list<int>(begin, [=]() { return from(begin + step, step, end); });
|
return lazy_list<int>([=]() { return some(mk_pair(begin, from(begin + step, step, end))); });
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_list<mpz> fact_list_core(mpz i, mpz n) {
|
lazy_list<mpz> fact_list_core(mpz i, mpz n) {
|
||||||
return lazy_list<mpz>(n, [=]() { return fact_list_core(i+1, n*(i+1)); });
|
return lazy_list<mpz>([=]() { return some(mk_pair(n, fact_list_core(i+1, n*(i+1)))); });
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_list<mpz> fact_list() {
|
lazy_list<mpz> fact_list() {
|
||||||
|
@ -51,36 +52,41 @@ lazy_list<int> mk_simple3() {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void display(lazy_list<T> const & l) {
|
void display(lazy_list<T> const & l) {
|
||||||
for (auto v : l) {
|
int buffer[20000];
|
||||||
|
int i = 0;
|
||||||
|
for_each(l, [&](T const & v) {
|
||||||
std::cout << v << " ";
|
std::cout << v << " ";
|
||||||
}
|
buffer[i] = i;
|
||||||
|
i++;
|
||||||
|
});
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
static void tst1() {
|
||||||
lean_assert(head(lazy_list<int>(10)) == 10);
|
lazy_list<int> l([]() { return some(mk_pair(10, lazy_list<int>())); });
|
||||||
lean_assert(!lazy_list<int>());
|
lazy_list<int> empty;
|
||||||
lean_assert(!tail(lazy_list<int>(10)));
|
lean_assert(l.pull()->first == 10);
|
||||||
lazy_list<int> l(-10, from(10, 20, 100));
|
lean_assert(!empty.pull());
|
||||||
l = cons(-20, l);
|
lean_assert(!l.pull()->second.pull());
|
||||||
lean_assert(head(l) == -20);
|
|
||||||
for (auto c : l) {
|
|
||||||
std::cout << c << "\n";
|
|
||||||
}
|
|
||||||
int i = 1;
|
|
||||||
for (auto c : take(30, zip(seq(1), fact_list()))) {
|
|
||||||
lean_assert(c.first == i);
|
|
||||||
std::cout << c.first << " " << c.second << "\n";
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
list<int> l2{1, 2, 3};
|
list<int> l2{1, 2, 3};
|
||||||
i = 1;
|
int i = 1;
|
||||||
for (auto c : to_lazy(l2)) {
|
for_each(to_lazy(l2), [&](int c) {
|
||||||
|
std::cout << "c: " << c << ", i: " << i << "\n";
|
||||||
lean_assert(c == i);
|
lean_assert(c == i);
|
||||||
i++;
|
i++;
|
||||||
}
|
});
|
||||||
display(mk_simple1(4));
|
display(mk_simple1(4));
|
||||||
display(mk_simple2());
|
display(mk_simple2());
|
||||||
display(take(12, mk_simple3()));
|
display(take(10, fact_list()));
|
||||||
|
display(take(20, mk_simple3()));
|
||||||
|
display(orelse(take(10, seq(1)), take(10, seq(100))));
|
||||||
|
display(orelse(take(10, seq(1)), lazy_list<int>()));
|
||||||
|
display(orelse(lazy_list<int>(), take(10, seq(100))));
|
||||||
|
display(orelse(take(0, seq(1)), take(10, seq(100))));
|
||||||
|
display(orelse(filter(take(100, seq(1)), [](int i) { return i < 0; }), take(10, seq(1000))));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
tst1();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,9 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
Author: Leonardo de Moura
|
Author: Leonardo de Moura
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "util/rc.h"
|
|
||||||
#include "util/debug.h"
|
#include "util/debug.h"
|
||||||
|
#include "util/rc.h"
|
||||||
|
#include "util/optional.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
/**
|
/**
|
||||||
|
@ -15,70 +16,45 @@ namespace lean {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class lazy_list {
|
class lazy_list {
|
||||||
public:
|
public:
|
||||||
class cell {
|
typedef optional<std::pair<T, lazy_list>> maybe_pair; // head and tail pair
|
||||||
|
private:
|
||||||
|
class cell_base {
|
||||||
MK_LEAN_RC();
|
MK_LEAN_RC();
|
||||||
void dealloc() { delete this; }
|
void dealloc() { delete this; }
|
||||||
T m_head;
|
|
||||||
public:
|
public:
|
||||||
cell(T const & h):m_rc(0), m_head(h) {}
|
cell_base():m_rc(0) {}
|
||||||
|
virtual ~cell_base() {}
|
||||||
|
virtual maybe_pair pull() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
class cell : public cell_base {
|
||||||
|
F m_f;
|
||||||
|
public:
|
||||||
|
cell(F && f):cell_base(), m_f(f) {}
|
||||||
virtual ~cell() {}
|
virtual ~cell() {}
|
||||||
T const & head() const { return m_head; }
|
virtual maybe_pair pull() const { return m_f(); }
|
||||||
virtual lazy_list tail() const { return lazy_list(); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
cell_base * m_ptr;
|
||||||
class explicit_cell : public cell {
|
|
||||||
lazy_list m_tail;
|
|
||||||
public:
|
|
||||||
explicit_cell(T const & h, lazy_list const & l):cell(h), m_tail(l) {}
|
|
||||||
virtual ~explicit_cell() {}
|
|
||||||
virtual lazy_list tail() const { return m_tail; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Tail>
|
|
||||||
class lazy_cell : public cell {
|
|
||||||
Tail m_tail;
|
|
||||||
public:
|
|
||||||
lazy_cell(T const & h, Tail const & t):cell(h), m_tail(t) {}
|
|
||||||
virtual ~lazy_cell() {}
|
|
||||||
virtual lazy_list tail() const { return m_tail(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
cell * m_ptr;
|
|
||||||
public:
|
public:
|
||||||
lazy_list():m_ptr(nullptr) {}
|
lazy_list():m_ptr(nullptr) {}
|
||||||
lazy_list(T const & h):m_ptr(new cell(h)) { m_ptr->inc_ref(); }
|
|
||||||
lazy_list(T const & h, lazy_list const & t):m_ptr(new explicit_cell(h, t)) { m_ptr->inc_ref(); }
|
|
||||||
template<typename F>
|
|
||||||
lazy_list(T const & h, F const & f):m_ptr(new lazy_cell<F>(h, f)) { m_ptr->inc_ref(); }
|
|
||||||
lazy_list(lazy_list const & s):m_ptr(s.m_ptr) { if (m_ptr) m_ptr->inc_ref(); }
|
lazy_list(lazy_list const & s):m_ptr(s.m_ptr) { if (m_ptr) m_ptr->inc_ref(); }
|
||||||
lazy_list(lazy_list && s):m_ptr(s.m_ptr) { s.m_ptr = nullptr; }
|
lazy_list(lazy_list && s):m_ptr(s.m_ptr) { s.m_ptr = nullptr; }
|
||||||
|
template<typename F> explicit lazy_list(F && f):m_ptr(new cell<F>(std::forward<F>(f))) { m_ptr->inc_ref(); }
|
||||||
~lazy_list() { if (m_ptr) m_ptr->dec_ref(); }
|
~lazy_list() { if (m_ptr) m_ptr->dec_ref(); }
|
||||||
|
|
||||||
lazy_list & operator=(lazy_list const & s) { LEAN_COPY_REF(list, s); }
|
lazy_list & operator=(lazy_list const & s) { LEAN_COPY_REF(lazy_list, s); }
|
||||||
lazy_list & operator=(lazy_list && s) { LEAN_MOVE_REF(list, s); }
|
lazy_list & operator=(lazy_list && s) { LEAN_MOVE_REF(lazy_list, s); }
|
||||||
|
|
||||||
operator bool() const { return m_ptr != nullptr; }
|
maybe_pair pull() const {
|
||||||
|
if (m_ptr)
|
||||||
|
return m_ptr->pull();
|
||||||
|
else
|
||||||
|
return maybe_pair();
|
||||||
|
}
|
||||||
|
|
||||||
friend T const & head(lazy_list const & l) { lean_assert(l); return l.m_ptr->head(); }
|
friend T head(lazy_list const & l) { return l.pull()->first; }
|
||||||
friend lazy_list tail(lazy_list const & l) { lean_assert(l); return l.m_ptr->tail(); }
|
friend lazy_list tail(lazy_list const & l) { return l.pull()->second; }
|
||||||
friend lazy_list cons(T const & h, lazy_list const & t) { return lazy_list(h, t); }
|
|
||||||
|
|
||||||
class iterator {
|
|
||||||
friend class lazy_list;
|
|
||||||
lazy_list m_it;
|
|
||||||
iterator(lazy_list const & it):m_it(it) {}
|
|
||||||
public:
|
|
||||||
iterator(iterator const & s):m_it(s.m_it) {}
|
|
||||||
iterator & operator++() { m_it = tail(m_it); return *this; }
|
|
||||||
iterator operator++(int) { iterator tmp(*this); operator++(); return tmp; }
|
|
||||||
bool operator==(iterator const & s) const { return m_it == s.m_it; }
|
|
||||||
bool operator!=(iterator const & s) const { return !operator==(s); }
|
|
||||||
T const & operator*() { lean_assert(m_it); return head(m_it); }
|
|
||||||
T const * operator->() { lean_assert(m_it); return &(head(m_it)); }
|
|
||||||
};
|
|
||||||
|
|
||||||
iterator begin() const { return iterator(*this); }
|
|
||||||
iterator end() const { return iterator(lazy_list()); }
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,78 +10,117 @@ Author: Leonardo de Moura
|
||||||
#include "util/list.h"
|
#include "util/list.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
|
template<typename T, typename F>
|
||||||
|
void for_each(lazy_list<T> l, F && f) {
|
||||||
|
while (true) {
|
||||||
|
auto p = l.pull();
|
||||||
|
if (p) {
|
||||||
|
f(p->first);
|
||||||
|
l = p->second;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
lazy_list<T> take(unsigned sz, lazy_list<T> l) {
|
lazy_list<T> take(unsigned sz, lazy_list<T> const & l) {
|
||||||
if (sz == 0 || !l) {
|
if (sz == 0) {
|
||||||
return lazy_list<T>();
|
return lazy_list<T>();
|
||||||
} else {
|
} else {
|
||||||
return lazy_list<T>(head(l), [=]() { return take(sz - 1, tail(l)); });
|
return lazy_list<T>([=]() {
|
||||||
}
|
auto p = l.pull();
|
||||||
}
|
if (p)
|
||||||
|
return some(mk_pair(p->first, take(sz - 1, p->second)));
|
||||||
template<typename T1, typename T2>
|
|
||||||
lazy_list<std::pair<T1, T2>> zip(lazy_list<T1> const & l1, lazy_list<T2> const & l2) {
|
|
||||||
if (l1 && l2) {
|
|
||||||
return lazy_list<std::pair<T1, T2>>(mk_pair(head(l1), head(l2)), [=]() { return zip(tail(l1), tail(l2)); });
|
|
||||||
} else {
|
|
||||||
return lazy_list<std::pair<T1, T2>>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
lazy_list<T> to_lazy(list<T> const & l) {
|
|
||||||
if (l)
|
|
||||||
return lazy_list<T>(head(l), [=]() { return to_lazy(tail(l)); });
|
|
||||||
else
|
else
|
||||||
|
return p;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
lazy_list<T> to_lazy(list<T> l) {
|
||||||
|
if (l) {
|
||||||
|
return lazy_list<T>([=]() {
|
||||||
|
return some(mk_pair(head(l), to_lazy(tail(l))));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
return lazy_list<T>();
|
return lazy_list<T>();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
lazy_list<T> append(lazy_list<T> const & l1, lazy_list<T> const & l2) {
|
lazy_list<T> append(lazy_list<T> const & l1, lazy_list<T> const & l2) {
|
||||||
if (!l1)
|
return lazy_list<T>([=]() {
|
||||||
return l2;
|
auto p = l1.pull();
|
||||||
else if (!l2)
|
if (!p)
|
||||||
return l1;
|
return l2.pull();
|
||||||
else
|
else
|
||||||
return lazy_list<T>(head(l1), [=]() { return append(tail(l1), l2); });
|
return some(mk_pair(p->first, append(p->second, l2)));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename F>
|
template<typename T>
|
||||||
lazy_list<T> map(lazy_list<T> const & l, F && f) {
|
lazy_list<T> orelse(lazy_list<T> const & l1, lazy_list<T> const & l2) {
|
||||||
if (!l)
|
return lazy_list<T>([=]() {
|
||||||
return l;
|
auto p = l1.pull();
|
||||||
|
if (!p)
|
||||||
|
return l2.pull();
|
||||||
else
|
else
|
||||||
return lazy_list<T>(f(head(l)), [=]() { return map(tail(l), f); });
|
return some(mk_pair(p->first, orelse(p->second, lazy_list<T>())));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
lazy_list<T> interleave(lazy_list<T> const & l1, lazy_list<T> const & l2) {
|
lazy_list<T> interleave(lazy_list<T> const & l1, lazy_list<T> const & l2) {
|
||||||
if (!l1)
|
return lazy_list<T>([=]() {
|
||||||
return l2;
|
auto p = l1.pull();
|
||||||
else if (!l2)
|
if (!p)
|
||||||
return l1;
|
return l2.pull();
|
||||||
else
|
else
|
||||||
return lazy_list<T>(head(l1), [=]() { return interleave(l2, tail(l1)); });
|
return some(mk_pair(p->first, interleave(l2, p->second)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename F>
|
||||||
|
lazy_list<T> map(lazy_list<T> const & l, F && f) {
|
||||||
|
return lazy_list<T>([=]() {
|
||||||
|
auto p = l.pull();
|
||||||
|
if (!p)
|
||||||
|
return p;
|
||||||
|
else
|
||||||
|
return some(mk_pair(f(p->first), map(p->second, f)));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename P>
|
template<typename T, typename P>
|
||||||
lazy_list<T> filter(lazy_list<T> const & l, P && p) {
|
lazy_list<T> filter(lazy_list<T> const & l, P && pred) {
|
||||||
if (!l)
|
return lazy_list<T>([=]() {
|
||||||
return l;
|
auto p = l.pull();
|
||||||
else if (p(head(l)))
|
if (!p)
|
||||||
return lazy_list<T>(head(l), [=]() { return filter(tail(l), p); });
|
return p;
|
||||||
|
else if (pred(p->first))
|
||||||
|
return some(mk_pair(p->first, p->second));
|
||||||
else
|
else
|
||||||
return filter(tail(l), p);
|
return filter(p->second, pred).pull();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename F>
|
template<typename T, typename F>
|
||||||
lazy_list<T> map_append_aux(lazy_list<T> const & h, lazy_list<T> const & l, F && f) {
|
lazy_list<T> map_append_aux(lazy_list<T> const & h, lazy_list<T> const & l, F && f) {
|
||||||
if (!l)
|
return lazy_list<T>([=]() {
|
||||||
return h;
|
auto p1 = h.pull();
|
||||||
else if (h)
|
if (p1) {
|
||||||
return lazy_list<T>(head(h), [=]() { return map_append_aux(tail(h), l, f); });
|
return some(mk_pair(p1->first, map_append_aux(p1->second, l, f)));
|
||||||
else
|
} else {
|
||||||
return map_append_aux(f(head(l)), tail(l), f);
|
auto p2 = l.pull();
|
||||||
|
if (p2) {
|
||||||
|
return map_append_aux(f(p2->first), p2->second, f).pull();
|
||||||
|
} else {
|
||||||
|
return typename lazy_list<T>::maybe_pair();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename F>
|
template<typename T, typename F>
|
||||||
|
|
|
@ -96,4 +96,9 @@ public:
|
||||||
return !o1.m_some || o1.m_value == o2.m_value;
|
return !o1.m_some || o1.m_value == o2.m_value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
optional<T> some(T && t) {
|
||||||
|
return optional<T>(std::forward<T>(t));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue