Chainlet Mini Language¶
Linking chainlets can be done using a simple grammar based on >>
and <<
operators [1].
These are used to create a directed connection between nodes.
You can even include forks and joins easily.
a >> b >> (c >> d, e >> f) >> g
This example links elements to form a directed graph:
Basic Links¶
Linking is based on a few, fundamental primitives. Combining them allows for complex data flows from simple building blocks.
Single Link - Pairs¶
The most fundamental operation is the directed link between parent and child. The direction of the link is defined by the direction of the operator.
parent >> child
child << parent
This creates and returns a chain linking parent and child.
Chained Link - Flat Chains¶
A pair can be linked again to extend the chain.
Adding a parent to a chain links it to the initial parent, while a new child is linked to the initial child.
Note that chains preserve only logical, but not syntactic orientation:
a >>
-linked chain can be extended via <<
and vice versa.
chain_a = parent >> child
chain_b = chain_a << parent2
chain_c = chain_b >> child2
Links can be chained directly; there is no need to store intermediate subchains if you do not use them.
chain_c = parent2 >> parent >> child >> child2
The above examples create the same underlying links between objects.
Chains represent only the link they have been created with.
Subsequent changes and links are not propagated.
Each of the objects chain_a
, chain_b
and chain_c
represent another part of the chain.
chain_d = parent2 >> parent >> child >> child2
# \-- chain_a --/
# \------------- chain_b --/
# \------------- chain_c ------------/
note: | Linking automatically flattens chains to create the longest possible chain.
This preserves equality but not identity of sub-chains.
This is similar to using the + operator on a list . |
---|
Links follow standard operation order, i.e. they are evaluated from left to right.
This can be confusing when mixing >>
and <<
in a single chain.
The following chain is equivalent to chain_c
.
chain_d = child << parent >> child2 << parent2
danger: | Mixing << and >> is generally a bad idea.
The use of >> is suggested, as it conforms to public and private interface implementations. |
---|
Forking and Joining Links - Bundles¶
Any chainlink can have an arbitrary number of parents and children.
This allows forking and joining the data stream.
Simply use a tuple()
, list()
or set()
as child or parent [2].
fork_chain = a >> (b >> c, d)
join_chain = (a, b >> c) >> d
The resulting chains are actually fully featured, directed graphs.
Links are agnostic with regard to how a group of elements is created. This allows you to use comprehensions and calls to generate forks and joins dynamically.
a >> {node(idx) for idx in range(3)}
note: | A tuple() , list() or set() is not by itself a chainlink.
It must be linked to an existing chainlink to trigger a conversion. |
---|
Advanced Linking Rules¶
Linking only guarantees element identity and a specific data flow graph.
This reflects that some dataflows which can be realised in multiple ways.
Several advanced rules allow chainlet
to superseed the default link process.
Link Operator Reflection¶
The >>
and <<
operators are subject to the regular operator reflection of Python [3].
In addition, there is an underlying linker which allows for similar behaviour beyond class hierarchies.
[1] | These are the __rshift__ and __lshift__ operators.
Overwriting these operators on objects changes their linking behaviour. |
[2] | There may be additional implications to using different types in the future. |
[3] | If the right operand’s type is a subclass of the left operand’s type and that subclass provides the reflected method for the operation, this method will be called before the left operand’s non-reflected method. This behavior allows subclasses to override their ancestors’ operations. |