gentyl
v1.1.0
Published
A Generator That You'll Love
Downloads
89
Maintainers
Readme
What is Structural Synthesis and what is it for?
The purpose of this tool is to provide a means of synthesizing and channeling structured data using a hierarchical state system. The system supports reactive IO and serialization of its dynamic generator objects.
Let's throw around some use cases, there are an unlimited number.
Gentyl can generate:
- events, worlds and enemies within games.
- language reflecting the structure of grammar.
- Test Cases in an Automated testing program.
- music and art with WebGL and Web Audio.
- solutions in an evolutionary computation algorithm.
- posts to appear in a feed.
- Whatever.. the list will grow!
Gentyl can also:
- Destructure
- Compose
- Store
- Stream processing
- Asynchonous input-output
Gentyl is:
- data focused model of execution
- dynamically typed
- built with typescript
- runnable on any javascript platform
- tested with jasmine
- process hierarchy
Basics
the fundamental unit is a G-node.
a G-node represents a generator object that can be resolved to produce objects.
G-nodes have 3 parts:
- Crown: | the compositional tree structure of what is generated.
- Form: | a description of how the node behaves, through Tractors and other properties.
- Context: | the items of state modified by and informing the results of Tractors. Appears as this.
each part is represented by an object argument
an example G-node used to generate cats with eventual exhaustion of names could look like this.
var gentyl = require("gentyl")
var G = gentyl.G
var catGen = G({
size:34,
ferocity:10,
name:G({},
{
r:function(obj, args){
return this.names.pop() || "puss"
}
},{
names:["Ben", "Lucy", "Magnus","Tiger"] //refers to here
}
)
},{
r:function(obj, args){
return `a size ${obj.size} cat with ${obj.ferocity} ferocity called ${obj.name}`
}
}).prepare();
catGen.resolve() // -> a size 34 cat with 10 ferocity called Tiger
catGen.resolve() // -> a size 34 cat with 10 ferocity called Magnus
although it is not necessary to call prepare() before resolve; it will call it internally if it is left out, it is an important stage in the setup of the node
Structure
G-nodes contain a map, array, or value that contain/is G-nodes and primitives. The recursive architecture means static values in the tree can be converted to dynamic generators at a whim, as seen with ferocity becoming an increasing function of 'intensity'. The functions can gain access to their parent node's state using context association mode strings =+ (track parent) or =_ (track root). Here 'intensity' is a root property that determines both size and ferocity.
function Linear(obj){
return obj.c + obj.m*this.intensity //This A
}
function randIntRng(obj){
return Math.floor(obj.min + Math.random()*(obj.max - obj.min))
}
var NamePicker = G({},
{
r:function(obj, args){
return this.names.pop() || "puss" // This B
}
},{
names:["Ben", "Lucy", "Magnus","Tiger"] //B refers to here
})
var catGen = G({
size:G({m:2, c:10}, {r:Linear, m:"=+"}),
ferocity:G({
m:2,
c:G({
min:5,
max:10,
},{
r:randIntRng
})
},{
r:Linear, //this A within
m:"=_"
}),
name:NamePicker
},{
r:function(obj, args){
this.intensity += 1; //This A
return `a size ${obj.size} cat with ${obj.ferocity} ferocity called ${obj.name}`
}
},{
intensity:0 //This A refers to here
}).prepare();
This G-Node will create cats like above with names like above but with sizes increasing in sequence (10, 12, 14..) and ferocity increasing but also with random influence, could be (6, 12, 9). Notice how easily nodes can be refactored the 'NamePicker' here can be used elsewhere without interfering with the state.
##Advanced the following will outline the advanced features, explaining the concepts and components involved. For detailed examples please refer to the jasmine specs.
Sharing State
Gentyl is caring about state, it doesn't marginalise it like other functional reactive technologies. State is controlled by localising it to each node and constructing a special this object. Children are able to access and modify the parent state by explicitly saying they will, but not the other way around, thus the state dependency structure matches the containment structure. There are three access modes and three ways to designate the source.
State Construction Modes.
|Mode | Symbol | Mnemonic | Meaning| |--------|:-:|-------------------|-----------------------| |Track | = | The train tracks | No modification only awareness of changes.| |Share | & | And we will work together | Child can modify the designated source.| |Inherit | (pipe) | It's you or me | The parent state is prototype/superclass.|
Designators
|type | symbol | Mnemonic | meaning | |----------|:-:|-----------------|----------------------------------------| |parent | + | up by one | designate the direct parent. | |root | _ | at the bottom | designate the root of the structure. | |arbitrary | x | back up x stops | designate x steps up the parent chain.|
for example ' &+ ' means share parent, ' |_ ' means inherit from the root. ' =2 ' means track my parents parent. These can be combined but there are rules about conflicting names and not sharing.
Tractors
At the heart of the execution model, doing all the heavy lifting, are Tractors. These are functions that are bound to the constructed context object of the G-node, that are called at some point in the execution of a G-node. They are called tractors because of how they form a 'tract' through a context from argument to return which is able to disturb the state within. They are always provided as unbound functions, typically not closures, they refer to the context through this. Tractors are always provided as a single letter property of the form object. The only possible tractors are currently resolver, carrier, selector and preparator at the core and injector, ejector and targeter in Gentyl's IO system.
Methods
These are the methods of the G-Node object, most of them perform recursively to capture the whole structure.