Last active
February 20, 2019 00:13
-
-
Save MarkRBM/71004abd0d5f379632da235fe946aad4 to your computer and use it in GitHub Desktop.
trees spec outline
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
I want to create a generalised tree datastructure that I can use to create arbitrary 'domain specific trees of a specifc type'. some of these `domain specific trees` can be nexted within different `domain specific trees`. some of them cannot and exist in isolation or in a group of tree types that are prevented from being in other tree types | |
step 1: a datastructure that is a Tree[A] where A is defined as a property of its root Node[A] | |
step 2: a special instance of the above which is Tree[EntityType] where an entity is a class that extends a specific trait, lets call that trait Entity and we can think of an entity as a row in a db with an id and EntityType as a table in a db. An example tree of this nature might look like so | |
-EntityTypeTree | |
-Country | |
-User | |
-Building | |
-Floor | |
-Room | |
-User | |
step3: the ability to use the above tree as the schema for the creation of a different tree a Tree[Assignment]. A example of such a tree might be | |
-AssignmentTree | |
-Ireland | |
-Johnny | |
-downtown hq | |
-floor 1 | |
-room 22 | |
-mary | |
-tomas | |
-floor 2 | |
-room 85 | |
-timmy | |
-uptown hq | |
-floor 1 | |
-room 76 | |
-mark | |
step4: add a new node type lets call it a BehviorNode that when added to a spot in an assignment tree it creates a subtree of that behavior type and the entity instance nodes inherit the behavior of that particular type of Behavior node | |
eg a ReservationBehaviorNode will give its child nodes the following behaviors in the following circumstances: | |
if its a User node that is not a leaf it will be given the ability to create reservations in any rooms in that User Nodes subtree | |
if its a UserNode that is a subnode of a room it will be given the ability to allow or block reservations made in that room by other users | |
if its a Room Node it will be able to have reservations made in it | |
Adding A ReservationBehavior Node to the tree in step 3 specifically might look like this | |
-AssignmentTree | |
-Ireland | |
-Johnny | |
-downtown hq | |
-ReservationBehaviorNode | |
-floor 1 | |
-room 22 | |
-mary | |
-tomas | |
-floor 2 | |
-room 85 | |
-timmy | |
-uptown hq | |
-floor 1 | |
-room 76 | |
-mark | |
step 5 I now want to be able to ask the tree above the following two questions | |
`Is johnny allowed to reserve room 22` and the answer should be no | |
but if the answer was yes I would then want to ask | |
`who should johhny ask to approve his reservation in room 22` | |
I should only be able to ask these questions of a tree of type ReservationBehavior Node | |
step 6 ultimately there should be arbitrary entity types arbitrary entity instances | |
and arbitrary behavior nodes, you can ask specific questions of specific behavior nodes | |
but in the short term even direction on how to create a specific tree with these properties | |
(has a structure that is defined by another tree, instances of entities in it and a way to | |
ask it questions about its entities would be a huge help. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
abstract class NodeType | |
sealed trait StructureTreeNodeType extends NodeType | |
sealed trait EntityTreeNodeType extends NodeType | |
//Some Enumberation that describes our entity Types | |
sealed trait EntityType extends StructureTreeNodeType | |
case object CountryT extends EntityType | |
case object BuildingT extends EntityType | |
case object FloorT extends EntityType | |
case object RoomT extends EntityType | |
case object UserT extends EntityType | |
//these can map to our Entities | |
sealed trait Entity extends EntityTreeNodeType { | |
def typee = this match { | |
case Country(_) => CountryT | |
case Building(_) => BuildingT | |
case Floor(_) => FloorT | |
case Room(_) => RoomT | |
case User(_) => UserT | |
} | |
} | |
case class Country(id: Long) extends Entity | |
case class Building(id: Long) extends Entity | |
case class Floor(id: Long) extends Entity | |
case class Room(id: Long) extends Entity | |
case class User(id: Long) extends Entity | |
//This can probably map to a center instance | |
sealed trait Behavior extends EntityTreeNodeType { | |
def centerId: Long | |
} | |
case class ServiceRequest(centerId: Long) extends Behavior | |
//this can map to a plain old category as they exist currently | |
sealed trait Arbitrary extends StructureTreeNodeType with EntityTreeNodeType | |
//generic representation of a tree parameterised by some type | |
// from now on they will be paramterised by their node type but they dont have to be | |
sealed trait Tree[A] { | |
def label: A | |
} | |
sealed trait Node[A] { | |
def children: Tree[A] | |
} | |
sealed trait Leaf[A] | |
//A tree that represents the structure of other trees | |
// its nodes and leaves can only be of type StructureTreeNodeType | |
sealed trait EntityStructureTree extends Tree[StructureTreeNodeType] | |
sealed trait StructureNode[A] extends EntityStructureTree with Node[A] | |
sealed trait StructureLeaf[A] extends EntityStructureTree with Leaf[A] | |
case class EntityStructureNode(label: EntityType, children: EntityStructureTree) extends StructureNode[StructureTreeNodeType] | |
case class EntityStructureLeaf(label: EntityType) extends StructureLeaf[EntityType] | |
case class ArbitraryStructureNode(label: Arbitrary, children: EntityStructureTree) extends StructureNode[StructureTreeNodeType] | |
case class ArbitraryStructureLeaf(label: Arbitrary) extends StructureLeaf[Arbitrary] | |
//A tree describing an entity assignments its nodes | |
// and leaves can only be of type EntityTreeNodeType | |
sealed trait AssignmentTree extends Tree[EntityTreeNodeType] | |
sealed trait AssignmentNode[A] extends AssignmentTree with Node[A] | |
sealed trait AssignmentLeaf[A] extends AssignmentTree with Leaf[A] | |
case class EntityNode(label: Entity, children: AssignmentTree) extends AssignmentNode[EntityTreeNodeType] | |
case class EntityLeaf(label: Entity) extends AssignmentLeaf[Entity] | |
case class ArbitraryNode(label: Arbitrary, children: AssignmentTree) extends AssignmentNode[EntityTreeNodeType] | |
case class ArbitraryLeaf(label: Arbitrary) extends AssignmentLeaf[Arbitrary] | |
case class BehaviorNode(label: Behavior, children: AssignmentTree) extends AssignmentNode[EntityTreeNodeType] | |
case class BehaviorLeaf(label: Behavior) extends AssignmentLeaf[Behavior] | |
// A structured version of the above Assignment tree, | |
// each node carries with it a EntityStructureTree that | |
// describes the tree structure from that node down | |
// you should only be able to create a tree of this type by | |
// providing an assignment tree and a structure tree but right now | |
//there is nothing stopping you from doing that | |
sealed trait StructuredAssignmentTree extends Tree[EntityTreeNodeType] { | |
def structure: EntityStructureTree | |
} | |
object StructuredAssignmentTree { | |
// take a structure and an assignment tree and return Either a Structured Assignment tree or an error message | |
def apply(structure: EntityStructureTree, t: AssignmentTree): Either[String, StructuredAssignmentTree] = (structure, t) match { | |
case (sn: EntityStructureNode, en: EntityNode) if (sn.label == en.label.typee) => apply(sn.children, en.children).map(c => StructuredEntityNode(en.label, sn, c)) | |
case (sl: EntityStructureLeaf, el: EntityLeaf) if (sl.label == el.label.typee) => Right(StructuredEntityLeaf(el.label, sl)) | |
case (asn: ArbitraryStructureNode, an: ArbitraryNode) => apply(asn.children, an.children).map(c => StructuredArbitraryLeaf(an.label, asn)) | |
case (sl: ArbitraryStructureLeaf, al: ArbitraryLeaf) => Right(StructuredArbitraryLeaf(al.label, sl)) | |
case (_, bn: BehaviorNode) => apply(structure, bn.children).map(c => StructuredBehaviorNode(bn.label, structure, c)) | |
case (_, bl: BehaviorLeaf) => Right(StructuredBehaviorLeaf(bl.label, structure)) | |
case _ => Left(s"${t.label} is not a ${structure.label}") | |
} | |
} | |
sealed trait StructuredNode[A] extends StructuredAssignmentTree with Node[A] | |
sealed trait StructuredLeaf[A] extends StructuredAssignmentTree with Leaf[A] | |
case class StructuredEntityNode(label: Entity, structure: EntityStructureTree, children: StructuredAssignmentTree) extends StructuredNode[EntityTreeNodeType] | |
case class StructuredEntityLeaf(label: Entity, structure: EntityStructureTree) extends StructuredLeaf[Entity] | |
case class StructuredArbitraryNode(label: Arbitrary, structure: EntityStructureTree, children: StructuredAssignmentTree) extends StructuredNode[EntityTreeNodeType] | |
case class StructuredArbitraryLeaf(label: Arbitrary, structure: EntityStructureTree) extends StructuredLeaf[Arbitrary] | |
case class StructuredBehaviorNode(label: Behavior, structure: EntityStructureTree, children: StructuredAssignmentTree) extends StructuredNode[EntityTreeNodeType] | |
case class StructuredBehaviorLeaf(label: Behavior, structure: EntityStructureTree) extends StructuredLeaf[Behavior] | |
//Our first structure, matches the one described in step 2 of the readme | |
val structure = EntityStructureNode( | |
UserT, | |
EntityStructureNode( | |
CountryT, | |
EntityStructureNode( | |
BuildingT, | |
EntityStructureNode( | |
FloorT, | |
EntityStructureNode( | |
RoomT, | |
EntityStructureLeaf( | |
UserT | |
) | |
) | |
) | |
) | |
) | |
) | |
val userOne = User(1) | |
val country = Country(1) | |
val building = Building(1) | |
val floor = Floor(1) | |
val room = Room(1) | |
val userTwo = User(2) | |
//our first assignment tree | |
val assignment = EntityNode( | |
userOne, | |
EntityNode( | |
country, | |
EntityNode( | |
building, | |
EntityNode( | |
floor, | |
EntityNode( | |
room, | |
EntityLeaf( | |
userTwo | |
) | |
) | |
) | |
) | |
) | |
) | |
// our first structured assignment tree, matches the one in step 4 of the read me | |
val structuredAssignment = StructuredAssignmentTree(structure, assignment) | |
println(structuredAssignment) | |
//This will contain functions that know how to traverse our StructuredTree and pluck out various | |
//paths, nodes and leaves | |
object BlackBox { | |
def getStructuredTree(nt: EntityTreeNodeType)(t: StructuredAssignmentTree): Option[StructuredAssignmentTree] = (nt, t) match { | |
case (e: Entity, en: EntityNode) if (e.typee == en.label.typee) => Some(en) | |
case (e: Entity, el: EntityLeaf) if (e.typee == el.label.typee) => Some(el) | |
case (a: Arbitrary, an: ArbitraryNode) => Some(an) | |
case (a: Arbitrary, al: ArbitraryLeaf) => Some(al) | |
case (b: Behavior, bn: BehaviorNode) => Some(bn) | |
case (b: Behavior, bl: BehaviorLeaf) => Some(bl) | |
case (_, n: StructuredNode[_]) => getStructuredTree(nt)(n.children) | |
case _ => None | |
} | |
} | |
//the rest of the iofficeconnect app will only | |
// have access to this interface object | |
//it will know what entities it needs to answer certain questions | |
//iofficeconnect needs to know and it will use the methods in Blackbox to | |
//get those answers | |
sealed trait RequestType | |
sealed trait Operator | |
object Interface { | |
def getOperatorForRequestType(rt: RequestType): Operator = ??? | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment