TreeExplorer: draft the core (explore) operation
The plan is to use a monad-like scheme, but allow for a lot of leeway with respect to the src and value types of the expand functor. A key idea is to allow for a *different* state core than used in the source
This commit is contained in:
parent
cbb35d7161
commit
d10c5a4f77
2 changed files with 192 additions and 101 deletions
|
|
@ -74,6 +74,7 @@
|
|||
#include "lib/error.hpp"
|
||||
#include "lib/meta/trait.hpp"
|
||||
#include "lib/meta/duck-detector.hpp"
|
||||
#include "lib/meta/function.hpp"
|
||||
#include "lib/iter-adapter.hpp"
|
||||
#include "lib/iter-stack.hpp"
|
||||
#include "lib/meta/trait.hpp" ////////////////TODO
|
||||
|
|
@ -83,76 +84,17 @@
|
|||
//#include <boost/utility/enable_if.hpp> //////////////TODO
|
||||
#include <stack> ////////////////TODO
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
||||
namespace iter_explorer {
|
||||
|
||||
////////////TODO
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Adapter to build a demand-driven tree expanding and exploring computation
|
||||
* based on a custom opaque _state core_. TreeExploer adheres to the _Monad_
|
||||
* pattern known from functional programming, insofar the _expansion step_ is
|
||||
* tied into the basic template by means of a function provided at usage site.
|
||||
*
|
||||
* @todo WIP -- preliminary draft as of 11/2017
|
||||
*/
|
||||
template<class SRC
|
||||
>
|
||||
class TreeExplorer
|
||||
// : public IterStateWrapper<typename SRC::value_type, SRC>
|
||||
: public SRC
|
||||
{
|
||||
|
||||
|
||||
public:
|
||||
typedef typename SRC::value_type value_type;
|
||||
typedef typename SRC::reference reference;
|
||||
typedef typename SRC::pointer pointer;
|
||||
|
||||
|
||||
/** by default create an empty iterator */
|
||||
TreeExplorer() { }
|
||||
|
||||
|
||||
/** wrap an iterator-like state representation
|
||||
* to build it into a monad. The resulting entity
|
||||
* is both an iterator yielding the elements generated
|
||||
* by the core, and it provides the (monad) bind operator.
|
||||
*/
|
||||
explicit
|
||||
TreeExplorer (SRC iterStateCore)
|
||||
: SRC{std::move (iterStateCore)}
|
||||
{ }
|
||||
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
using std::move;
|
||||
using std::forward;
|
||||
using std::function;
|
||||
|
||||
namespace iter_explorer {
|
||||
|
||||
/////TODO RLY?
|
||||
|
||||
// using util::unConst;
|
||||
// using lib::meta::enable_if;
|
||||
// using lib::meta::disable_if;
|
||||
// using std::function;
|
||||
// using meta::_Fun;
|
||||
|
||||
template<class CON>
|
||||
using iterator = typename meta::Strip<CON>::TypeReferred::iterator;
|
||||
template<class CON>
|
||||
|
|
@ -182,6 +124,7 @@ namespace lib {
|
|||
|
||||
}//(End) namespace iter_explorer : predefined policies and configurations
|
||||
|
||||
|
||||
namespace { // TreeExplorer traits
|
||||
|
||||
using meta::enable_if;
|
||||
|
|
@ -244,6 +187,117 @@ namespace lib {
|
|||
|
||||
|
||||
|
||||
namespace iter_source {
|
||||
|
||||
template<class EXP, class SIG, class SEL =void>
|
||||
class Expander
|
||||
: public EXP
|
||||
{
|
||||
function<SIG> expandChildren_;
|
||||
|
||||
public:
|
||||
Expander() =default;
|
||||
// inherited default copy operations
|
||||
|
||||
template<typename FUN>
|
||||
Expander (EXP&& parentExplorer, FUN&& expandFunctor)
|
||||
: EXP{move (parentExplorer)}
|
||||
, expandChildren_{forward<FUN> (expandFunctor)}
|
||||
{ }
|
||||
|
||||
|
||||
/** core operation: expand current head element */
|
||||
Expander&
|
||||
expand()
|
||||
{
|
||||
UNIMPLEMENTED ("expand-children core operation");
|
||||
}
|
||||
|
||||
/** diagnostics: current level of nested child expansion */
|
||||
size_t
|
||||
depth() const
|
||||
{
|
||||
UNIMPLEMENTED ("implementation of the expand mechanics");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Adapter to build a demand-driven tree expanding and exploring computation
|
||||
* based on a custom opaque _state core_. TreeExploer adheres to the _Monad_
|
||||
* pattern known from functional programming, insofar the _expansion step_ is
|
||||
* tied into the basic template by means of a function provided at usage site.
|
||||
*
|
||||
* @todo WIP -- preliminary draft as of 11/2017
|
||||
*/
|
||||
template<class SRC
|
||||
>
|
||||
class TreeExplorer
|
||||
: public SRC
|
||||
{
|
||||
|
||||
|
||||
public:
|
||||
typedef typename SRC::value_type value_type;
|
||||
typedef typename SRC::reference reference;
|
||||
typedef typename SRC::pointer pointer;
|
||||
|
||||
|
||||
/** by default create an empty iterator */
|
||||
TreeExplorer() { }
|
||||
|
||||
// default copy acceptable (unless prohibited by nested state core)
|
||||
|
||||
|
||||
/** wrap an iterator-like state representation
|
||||
* to build it into a monad. The resulting entity
|
||||
* is both an iterator yielding the elements generated
|
||||
* by the core, and it provides the (monad) bind operator.
|
||||
*/
|
||||
explicit
|
||||
TreeExplorer (SRC iterStateCore)
|
||||
: SRC{std::move (iterStateCore)}
|
||||
{ }
|
||||
|
||||
|
||||
/* ==== Builder functions ==== */
|
||||
|
||||
template<class FUN>
|
||||
auto
|
||||
expand (FUN&& expandFunctor)
|
||||
{
|
||||
using FunSig = typename meta::_Fun<FUN>::Sig;
|
||||
using This = typename meta::Strip<decltype(*this)>::TypeReferred;
|
||||
|
||||
return iter_source::Expander<This, FunSig> {move(*this), forward<FUN>(expandFunctor)};
|
||||
}
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace iter_explorer {
|
||||
|
||||
/////TODO RLY?
|
||||
|
||||
// using util::unConst;
|
||||
// using lib::meta::enable_if;
|
||||
// using lib::meta::disable_if;
|
||||
// using std::function;
|
||||
// using meta::_Fun;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ==== convenient builder free functions ==== */
|
||||
|
||||
|
|
|
|||
|
|
@ -86,30 +86,30 @@ namespace test{
|
|||
* This iteration _"state core" type_ describes
|
||||
* a sequence of numbers yet to be delivered.
|
||||
*/
|
||||
class State
|
||||
class CountDown
|
||||
{
|
||||
uint p,e;
|
||||
|
||||
public:
|
||||
State(uint start =0, uint end =0)
|
||||
CountDown(uint start =0, uint end =0)
|
||||
: p(start)
|
||||
, e(end)
|
||||
{ }
|
||||
|
||||
friend bool
|
||||
checkPoint (State const& st)
|
||||
checkPoint (CountDown const& st)
|
||||
{
|
||||
return st.p > st.e;
|
||||
}
|
||||
|
||||
friend uint&
|
||||
yield (State const& st)
|
||||
yield (CountDown const& st)
|
||||
{
|
||||
return util::unConst(checkPoint(st)? st.p : st.e);
|
||||
}
|
||||
|
||||
friend void
|
||||
iterNext (State & st)
|
||||
iterNext (CountDown & st)
|
||||
{
|
||||
if (not checkPoint(st)) return;
|
||||
--st.p;
|
||||
|
|
@ -123,33 +123,19 @@ namespace test{
|
|||
* The tests will dress up this source sequence in various ways.
|
||||
*/
|
||||
class NumberSequence
|
||||
: public IterStateWrapper<uint, State>
|
||||
: public IterStateWrapper<uint, CountDown>
|
||||
{
|
||||
|
||||
public:
|
||||
explicit
|
||||
NumberSequence(uint end = 0)
|
||||
: IterStateWrapper<uint,State> (State(0,end))
|
||||
: IterStateWrapper<uint,CountDown> (CountDown(0,end))
|
||||
{ }
|
||||
NumberSequence(uint start, uint end)
|
||||
: IterStateWrapper<uint,State> (State(start,end))
|
||||
: IterStateWrapper<uint,CountDown> (CountDown(start,end))
|
||||
{ }
|
||||
};
|
||||
|
||||
inline NumberSequence
|
||||
seq (uint end)
|
||||
{
|
||||
return NumberSequence(end);
|
||||
}
|
||||
|
||||
inline NumberSequence
|
||||
seq (uint start, uint end)
|
||||
{
|
||||
return NumberSequence(start, end);
|
||||
}
|
||||
|
||||
NumberSequence NIL_Sequence;
|
||||
|
||||
|
||||
|
||||
/** Diagnostic helper: "squeeze out" the given iterator
|
||||
|
|
@ -232,9 +218,9 @@ namespace test{
|
|||
verify_wrappedState();
|
||||
verify_wrappedIterator();
|
||||
|
||||
verify_mapOperation();
|
||||
verify_expandOperation();
|
||||
verify_expandMapCombination();
|
||||
verify_transformOperation();
|
||||
verify_combinedExpandTransform();
|
||||
|
||||
verify_depthFirstExploration();
|
||||
demonstrate_LayeredEvaluation();
|
||||
|
|
@ -248,7 +234,7 @@ namespace test{
|
|||
void
|
||||
verify_wrappedState()
|
||||
{
|
||||
auto ii = treeExplore (State{5,0});
|
||||
auto ii = treeExplore (CountDown{5,0});
|
||||
CHECK (!isnil (ii));
|
||||
CHECK (5 == *ii);
|
||||
++ii;
|
||||
|
|
@ -260,11 +246,11 @@ namespace test{
|
|||
VERIFY_ERROR (ITER_EXHAUST, *ii );
|
||||
VERIFY_ERROR (ITER_EXHAUST, ++ii );
|
||||
|
||||
ii = treeExplore (State{5});
|
||||
ii = treeExplore (CountDown{5});
|
||||
CHECK (materialise(ii) == "5-4-3-2-1");
|
||||
ii = treeExplore (State{7,4});
|
||||
ii = treeExplore (CountDown{7,4});
|
||||
CHECK (materialise(ii) == "7-6-5");
|
||||
ii = treeExplore (State{});
|
||||
ii = treeExplore (CountDown{});
|
||||
CHECK ( isnil (ii));
|
||||
CHECK (!ii);
|
||||
}
|
||||
|
|
@ -302,19 +288,70 @@ namespace test{
|
|||
|
||||
|
||||
|
||||
/** @test pipe each result through a transformation function
|
||||
*/
|
||||
void
|
||||
verify_mapOperation()
|
||||
{
|
||||
UNIMPLEMENTED("map function onto the results");
|
||||
}
|
||||
|
||||
|
||||
/** @test use a preconfigured "expand" functor to recurse into children
|
||||
* The `expand()` builder function predefines a way how to _expand_ the current
|
||||
* head element of the iteration. However, expansion does not happen automatically,
|
||||
* rather, it needs to be invoked by the client, similar to increment of the iterator.
|
||||
* When expanding, the current head element is consumed and fed into the expand functor;
|
||||
* the result of this functor invocation is injected instead into the result sequence,
|
||||
* and consequently this result needs to be again an iterable with compatible value type.
|
||||
* Conceptually, the evaluation _forks into the children of the expanded element_, before
|
||||
* continuing with the successor of the expansion point. Obviously, expansion can be applied
|
||||
* again on the result of the expansion, possibly leading to a tree of side evaluations.
|
||||
*/
|
||||
void
|
||||
verify_expandOperation()
|
||||
{
|
||||
auto ii = treeExplore(CountDown{5})
|
||||
.expand([](uint j){ return CountDown{j-1}; })
|
||||
;
|
||||
|
||||
CHECK (!isnil (ii));
|
||||
CHECK (5 == *ii);
|
||||
++ii;
|
||||
CHECK (4 == *ii);
|
||||
|
||||
CHECK (0 == ii.depth());
|
||||
ii.expand();
|
||||
CHECK (3 == *ii);
|
||||
CHECK (1 == ii.depth());
|
||||
++ii;
|
||||
CHECK (2 == *ii);
|
||||
CHECK (1 == ii.depth());
|
||||
ii.expand();
|
||||
CHECK (1 == *ii);
|
||||
CHECK (2 == ii.depth());
|
||||
++ii;
|
||||
CHECK (1 == *ii);
|
||||
CHECK (1 == ii.depth());
|
||||
++ii;
|
||||
CHECK (3 == *ii);
|
||||
CHECK (0 == ii.depth());
|
||||
CHECK (materialise(ii) == "3-2-1");
|
||||
ii.expand();
|
||||
CHECK (1 == ii.depth());
|
||||
CHECK (materialise(ii) == "2-1-2-1");
|
||||
++++ii;
|
||||
CHECK (0 == ii.depth());
|
||||
CHECK (materialise(ii) == "2-1");
|
||||
ii.expand();
|
||||
CHECK (1 == ii.depth());
|
||||
CHECK (materialise(ii) == "1-1");
|
||||
++ii;
|
||||
CHECK (0 == ii.depth());
|
||||
CHECK (1 == *ii);
|
||||
CHECK (materialise(ii) == "1");
|
||||
ii.expand();
|
||||
CHECK (isnil (ii));
|
||||
VERIFY_ERROR (ITER_EXHAUST, *ii );
|
||||
VERIFY_ERROR (ITER_EXHAUST, ++ii );
|
||||
}
|
||||
|
||||
|
||||
/** @test pipe each result through a transformation function
|
||||
*/
|
||||
void
|
||||
verify_transformOperation()
|
||||
{
|
||||
UNIMPLEMENTED("expand children");
|
||||
}
|
||||
|
|
@ -323,7 +360,7 @@ namespace test{
|
|||
/** @test combie the recursion into children with a tail mapping operation
|
||||
*/
|
||||
void
|
||||
verify_expandMapCombination()
|
||||
verify_combinedExpandTransform()
|
||||
{
|
||||
UNIMPLEMENTED("combine child expansion and result mapping");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue