diff --git a/src/lib/iter-tree-explorer.hpp b/src/lib/iter-tree-explorer.hpp index c2d10b94c..41174c927 100644 --- a/src/lib/iter-tree-explorer.hpp +++ b/src/lib/iter-tree-explorer.hpp @@ -22,11 +22,12 @@ /** @file iter-tree-explorer.hpp ** Building tree expanding and backtracking evaluations within hierarchical scopes. - ** Based on the Lumiera Forward Iterator concept and using the basic IterAdaptor templates, - ** 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 + ** Based on the *Lumiera Forward Iterator* concept and using the basic IterAdaptor templates, + ** these components allow to implement typical evaluation strategies, like conditional expanding + ** or depth-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 IterStateWrapper, which is one of the basic helper templates + ** The implementation is based on the idea of a "state core", which is wrapped right into the iterator + ** itself (value semantics) -- similar to the IterStateWrapper, which is one of the basic helper templates ** provided by iter-adapter.hpp. ** ** @remark as of 2017, this template, as well as the initial IterExplorer (draft from 2012) can be @@ -38,13 +39,14 @@ ** separate the _mechanics of evaluation_ from the actual logic of the target domain. ** ** # Iterators as Monad - ** The fundamental idea behind the implementation technique used here is the \em Monad pattern - ** known from functional programming. A Monad is a (abstract) container created by using some specific functions. - ** This is an rather abstract concept with a wide variety of applications (things like IO state, parsers, combinators, + ** The fundamental idea behind the implementation technique used here is the _Monad pattern_ + ** known from functional programming. A Monad is a container holding some arbitrarily typed base value; the monad can + ** be seen as "amplifying" and enhancing the contained base value by attaching additional properties or capabilities + ** This is a rather detached concept with a wide variety of applications (things like IO state, parsers, combinators, ** calculations with exception handling but also simple data structures like lists or trees). The key point with any - ** monad is the ability to \em bind a function into the monad; this function will work on the \em internals of the - ** monad and produce a modified new monad instance. In the simple case of a list, "binding" a function - ** basically means to map the function onto the elements in the list. + ** monad is the ability to _bind a function_ into the monad; this function will work on the _contained base values_ + ** and produce a modified new monad instance. In the simple case of a list, "binding" a function basically means + ** to _map the function onto_ the elements in the list. ** ** ## Rationale ** The primary benefit of using the monad pattern is to separate the transforming operation completely from @@ -57,6 +59,22 @@ ** - and this evaluation needs to be done asynchronously and in parallel (no locking, immutable data) ** - and a partial evaluation needs to be stored as continuation (not relying on the stack for partial results) ** + ** # A Pipeline builder + ** Based on such concepts, structures and evaluation patterns, the TreeExplorer serves the purpose to provide + ** building blocks to assemble a _processing pipeline_, where processing will happen _on demand,_ while iterating. + ** TreeExplorer itself is both a Lumiera Forward Iterator based on some wrapped data source, and at the same time + ** it is a builder to chain up processing steps to work on the data pulled from that source. These processing steps + ** are attached as _decorators_ wrapping the source, in the order the corresponding builder functions were invoked. + ** - the _expand operation_ installs a function to consume one element and replace it by the sequence of elements + ** (``children'') produced by that _»expansion functor«_. But this expansion does not happen automatically and + ** on each element, rather it is triggered by issuing a dedicated `expandChildren()` call on the processing + ** pipeline. Thus, binding the expansion functor has augmented the data source with the ability to explore + ** some part in more detail _when required. + ** - the _transform operation_ installs a function to be mapped onto each element retrieved from the underlying source + ** - in a similar vein, the _filter operation_ binds a predicate to decide about using or discarding data + ** - in concert, expand- and transform operation allow to build hierarchy evaluation algorithms without exposing + ** any knowledge regarding the concrete hierarchy used and explored as data source. + ** ** @todo WIP-WIP-WIP initial draft as of 11/2017 ** ** @see IterTreeExplorer_test @@ -229,6 +247,8 @@ namespace lib { }//(End) namespace iter_explorer : predefined policies and configurations + + namespace { // TreeExplorer traits using meta::enable_if; @@ -496,6 +516,8 @@ namespace lib { iterNext(); // consume current head element if (not isnil(expanded)) expansions_.push (move(expanded)); + + SRC::expandChildren(); } /** diagnostics: current level of nested child expansion */ diff --git a/tests/library/iter-tree-explorer-test.cpp b/tests/library/iter-tree-explorer-test.cpp index 6b4d3bafa..76b67620b 100644 --- a/tests/library/iter-tree-explorer-test.cpp +++ b/tests/library/iter-tree-explorer-test.cpp @@ -572,10 +572,14 @@ namespace test{ * in that case it might even happen that the downstream consumer does not even see the * items resulting from child expansion, because they are evaluated and then filtered * away by a transformer and filter placed in between. - * @note a corollary of the aforementioned is the observation that having several expand - * layers is rather not useful in practice. Due to the nested inheritance structure - * of the assembled TreeExplorer, it is the expansion layer most on top in the chain - * who will receive the `expandChildren()` call. + * @note as a consequence of the flexible automatic adapting of bound functors, it is + * possible for bound functors within different "layers" to collaborate, based on + * additional knowledge regarding the embedded data source internals. This test + * demonstrates a transform functor, which takes the _source iterator_ as argument + * and invokes `it.expandChildren()` to manipulate the underlying evaluation. + * However, since the overall evaluation is demand driven, there are inherent + * limitations to such a setup, which bends towards fragility when leaving + * the realm of pure functional evaluation. */ void verify_combinedExpandTransform() @@ -590,13 +594,13 @@ namespace test{ ++ii; CHECK (8 == *ii); ii.expandChildren(); - cout << materialise(ii) < - + @@ -5719,10 +5719,11 @@ - - + + - + + @@ -6247,9 +6248,10 @@ - - - + + + + @@ -6257,12 +6259,16 @@ - + + - - + + + + +