draft the IterExplorer design

the tricky part seems to be how to combine the
source iterators into a new monad instance, while
keeping this "Combinator" Strategy configurable

...just passes the compiler, while still lacking
even the generic implementation of joining
together the source iterators
This commit is contained in:
Fischlurch 2012-05-23 04:06:24 +02:00
parent 45f4c96c6f
commit eedcd69941
3 changed files with 281 additions and 32 deletions

View file

@ -26,7 +26,7 @@
** these components allow to implement typical evaluation strategies, like e.g. depth-first or
** breadth-first exploration of a hierarchical structure. Since the access to this structure is
** abstracted through the underlying iterator, what we effectively get is a functional datastructure.
** The implementation is based on the IterableStateWrapper, which is one of the basic helper templates
** The implementation is based on the IterStateWrapper, which is one of the basic helper templates
** provided by iter-adapter.hpp.
**
** @see IterExplorer_test.cpp
@ -43,42 +43,290 @@
#include "lib/error.hpp"
//#include "lib/bool-checkable.hpp"
#include "lib/meta/function.hpp"
#include "lib/iter-adapter.hpp"
//#include <boost/type_traits/remove_const.hpp>
namespace lib {
namespace { // internal helpers
using std::tr1::function;
using meta::FunctionSignature;
/**
* Helper to dissect an arbitrary function signature,
* irrespective if the parameter is given as function reference,
* function pointer, member function pointer or functor object.
* The base case assumes a (language) function reference.
*/
template<typename SIG>
struct _Fun
{
typedef typename FunctionSignature<function<SIG> >::Ret Ret;
typedef typename FunctionSignature<function<SIG> >::Args Args;
};
/** Specialisation for using a function pointer */
template<typename SIG>
struct _Fun<SIG*>
{
typedef typename FunctionSignature<function<SIG> >::Ret Ret;
typedef typename FunctionSignature<function<SIG> >::Args Args;
};
/** Specialisation for passing a functor */
template<typename SIG>
struct _Fun<function<SIG> >
{
typedef typename FunctionSignature<function<SIG> >::Ret Ret;
typedef typename FunctionSignature<function<SIG> >::Args Args;
};
}
namespace iter_explorer {
template<class FUN>
class DefaultCombinator;
}
/**
* Adapter for building....
* TODO write type comment
* Adapter for using an Iterator in the way of a Monad
* This allows to "bind" or "flatMap" a functor, thereby creating
* a derived version of the iterator, yielding the (flattened) combination
* of all the results generated by this bound functor. The rationale is
* to apply some exploration or expansion pattern on the elements of the
* source sequence (source iterator) -- while completely separating out
* the \em mechanics how to treat and combine individual elements.
*
* \par implementation approach
* IterExplorer is a thin wrapper, based on IterStateWrapper; thus the assumption
* is for the actual elements to be generated by a "state core", which is embedded
* right into each instance. To provide the monad bind operator \c >>= , we need
* the help of a strategy template, the so called \em Combinator. This strategy
* contains the details how to combine the results of various iterators and
* to join them together into a single new IterExplorer instance. Thus, obviously
* this Combinator strategy template relies on additional knowledge about the
* source iterator's implementation. Such is unavoidable, since C++ isn't a
* functional programming language.
*
* When invoking the bind (flat map) operator, a suitably represented \em functor
* is embedded into an instance of the Combinator template. The resulting object
* becomes the state core of the new IterExplorer object returned as result.
* So the result \em is an iterator, but -- when "pulled" -- it will in turn
* pull from the source iterator and feed the provided elements through the
* \em exploration functor, which this way has been \em bound into the resulting
* monad. The purpose of the Combinator strategy is to join together various
* resulting iterators, thereby "flattening" one level of "monad packaging"
* (hence the name "flat map operator").
*
* @remarks figuring out what happens here just from the code might lead to confusion.
* You really need to grasp the monad concept first, which is a design pattern
* commonly used in functional programming. For the practical purpose in question
* here, you might consider it a "programmable semicolon": it links together a
* chain of operations detailed elsewhere, and provided in a dynamic fashion
* (as functor at runtime). More specifically, these operations will expand
* and explore a dynamic source data set on the fly. Notably this allows
* us to handle such an "exploration" on-the-fly, without the need to
* allocate heap memory to store intermediary results, but also without
* using the stack and recursive programming.
*/
template<class POS, class CON>
template<class SRC
,template<class> class _COM_ = iter_explorer::DefaultCombinator
>
class IterExplorer
// : public lib::BoolCheckable<IterAdapter<POS,CON> >
: public IterStateWrapper<typename SRC::value_type, SRC>
{
// CON source_;
// mutable POS pos_;
typedef typename SRC::value_type value_type;
typedef typename SRC::reference reference;
public:
// typedef typename iter::TypeBinding<POS>::pointer pointer;
// typedef typename iter::TypeBinding<POS>::reference reference;
// typedef typename iter::TypeBinding<POS>::value_type value_type;
/** 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
IterExplorer (SRC const& iterStateCore)
: IterStateWrapper<value_type, SRC> (iterStateCore)
{ }
protected: /* === xxx === */
/** monad bind ("flat map") operator */
template<class FUN>
IterExplorer<_COM_<FUN>, _COM_>
operator >>= (FUN explorer)
{
typedef _COM_<FUN> Combinator;
return IterExplorer(
Combinator(explorer)
.startWith( explorer(accessFirstElement()))
.followUp (accessRemainingElements()));
}
/** */
private:
reference
accessFirstElement()
{
return this->operator* ();
}
IterExplorer&
accessRemainingElements()
{
this->operator++ ();
return *this;
}
};
namespace iter_explorer { ///< predefined policies and configurations
/**
* a generic "Combinator strategy" for IterExplorer.
* This fallback solution just assumes that the source is a
* Lumiera Forward Iterator -- consequently we need to do heap
* allocations behind the scenes, as the size and structure of
* the expansion results is determined at runtime.
* @note the whole purpose of IterExplorer is to be more efficient
* then this fallback, thus requiring more specific Combinator
* strategies, able to exploit specific knowledge of the
* source iterator's implementation.
*/
template<class FUN>
class DefaultCombinator
{
typedef typename _Fun<FUN>::Ret ResultIter;
public:
typedef typename ResultIter::value_type value_type;
typedef typename ResultIter::reference reference;
typedef typename ResultIter::pointer pointer;
DefaultCombinator(FUN explorer)
{
UNIMPLEMENTED ("representation of the sequence of partial results");
}
DefaultCombinator &
startWith (ResultIter firstExplorationResult)
{
UNIMPLEMENTED ("DefaultCombinator: yield first result");
return *this;
}
template<class SRC>
DefaultCombinator&
followUp (SRC followUpSourceElements)
{
UNIMPLEMENTED ("DefaultCombinator: follow up iteration");
return *this;
}
/* === Iteration control API for IterStateWrapper== */
friend bool
checkPoint (DefaultCombinator const& sequence)
{
UNIMPLEMENTED ("how to determine exhausted state on the combined results");
return false;
}
friend reference
yield (DefaultCombinator const& sequence)
{
UNIMPLEMENTED ("how to yield a result from the combined iterator");
}
friend void
iterNext (DefaultCombinator & sequence)
{
UNIMPLEMENTED ("increment the source iterator and switch to the next partial result sequence if necessary");
}
};
/**
* Helper template to bootstrap a chain of IterExplorers.
* This is a "state corer", which basically just wraps a given
* source iterator and provides the necessary free functions
* (iteration control API) to use this as iteration state
* within IterExplorer.
* @note to ease building such an initial version of the Iterator Monad,
* use the free function \link #exploreIter \endlink
*/
template<class IT>
class WrappedSequence
: public IT
{
public:
WrappedSequence()
: IT()
{ }
WrappedSequence(IT const& srcIter)
: IT(srcIter)
{ }
/* === Iteration control API for IterStateWrapper == */
inline bool
checkPoint (WrappedSequence const& sequence)
{
return bool(sequence);
}
inline typename IT::reference
yield (WrappedSequence const& sequence)
{
return *sequence;
}
inline void
iterNext (WrappedSequence & sequence)
{
++sequence;
}
};
}//(End) namespace iter_explorer : predefined policies and configurations
template<class IT>
IterExplorer<iter_explorer::WrappedSequence<IT> >
exploreIter (IT const& srcSeq)
{
return IterExplorer<iter_explorer::WrappedSequence<IT> > (srcSeq);
}

View file

@ -520,6 +520,13 @@ namespace lib {
return !head_;
}
private:
/**
* Iteration is just following the single linked list.
* We encapsulate this simple pointer into a dedicated marker type
* to ease the handling and mixing of iterators and const iterators.
* (Explanation: IterationState depends on our type parameters...)
*/
struct IterationState
{
N* node;
@ -535,7 +542,8 @@ namespace lib {
}
};
typedef IterStateWrapper<N, IterationState> iterator;
public:
typedef IterStateWrapper< N, IterationState> iterator;
typedef IterStateWrapper<const N, IterationState> const_iterator;

View file

@ -38,20 +38,6 @@
namespace lib {
namespace iter {
template<>
struct TypeBinding<uint>
{
typedef uint value_type;
typedef uint const& reference;
typedef uint const* pointer;
};
}
namespace test{
using ::Test;
@ -71,6 +57,10 @@ namespace test{
// uint NUM_ELMS = 10;
/**
* This iteration state type describes
* a sequence of numbers still to be delivered.
*/
class State
{
uint p,e;
@ -103,7 +93,10 @@ namespace test{
/** */
/**
* A straight number sequence as basic test iterator.
* The tests will dress up this source sequence in various ways.
*/
class NumberSequence
: public IterStateWrapper<uint, State>
{
@ -117,7 +110,7 @@ namespace test{
: IterStateWrapper<uint,State> (State(start,end))
{ }
};
inline NumberSequence
seq (uint end)
{
@ -135,7 +128,7 @@ namespace test{
/** Diagnostic helper: "squeeze out" the given iterator
* and join all yielded elements into a string
* and join all the elements yielded into a string
*/
template<class II>
inline string
@ -150,7 +143,7 @@ namespace test{
return buff.str();
}
} // (END) impl test dummy container
} // (END) test helpers