proj-oot-ootDataThoughts

---

maybe in line with the 'everything is an interface' policy, when a function needs to create a new instance of a data type, it doesn't provide the implementation type; rather, the implementation type must be passed in from the outside. It can, however, make these type arguments optional keyworrd args, providing a default that the caller can choose not to override.

perhaps in line with this, top-level functions should also be required not to have implementation type constants, just like lower level ones; the type constants passed by the 'caller' are provided via some externally configured 'environment'.

---

so in general, perhaps we should supply an external configuration 'environment' and infrastructure for configuring it, similar to python's paste/WSGI

(i get the sense that the java web frameworks are the most developed along these lines, should look into what they do)

---

in languages like Haskell, an important think is to have ADTs, e.g. lists, which are discriminated unions/tagged unions (eg each instance of a List is either a Nil or a Cons), and this is exhaustive (each List is exactly one of Nil or Cons) and can be 'case'd upon (eg you can say switch l1..case Nil: ...; case Cons:... ), destructured (if a List is a Cons, you can tell what the arguments to the Cons constructor were, and get those back by binding a pattern to it eg. (l1_head, l1_tail) = Cons(l1))

Oot should probably have these too. How to square that with Everything Is An Interface? Well, we make the ADT not actually corresponding to the data implementation, but rather only an interface itself. So, e.g. something that supports the List interface must provide __-prefixed functions like __which, which returns which List constructor a value is, and __constructorArgs, which give the constructor args that would have created this value.

Note that this requirement is itself just an interface signature, so it can fit within our usual structural typing pattern as a 'graph regex'/structural pattern.

Note also that the List interface support of some data value is per-view. There may be multiple views onto the same data value which support List, and some that don't, for example.

---

so, in order to discourage functions from discarding metadata from their inputs by using new() to create new objects (e.g. in a list filtering function, even if the algorithm is to start with an empty list and then add in those items that pass the filter, you want the hidden metadata that was attached to the input list in other views to be copied to the new, empty list), we could: not provide a direct way to construct new objects of a certain type; provide a "new" but this is really "clone", and it requires a prototype to clone. In generic (parametrically polymorphic) functions, this makes it easier to type new(x), which is the right thing, rather than new(getDefault(type(x))), which would give an empty list without metadata.

---

trying to find the name of the idea of 'graphs with ports'

see

http://math.stackexchange.com/questions/1118344/what-is-the-name-of-a-graph-structure-with-ports

this could be the mechanism for describing data structure shapes within oot, which is closely related to views

also it suggests an addition the the oot graph data structure; not just a reifiable directed labeled hyper multigraph (was that everything or did i miss something), but a ported reifiable directed labeled hyper multigraph. Heck that's getting pretty long. We might just call it an 'oot graph'.

---

i guess Python's truthiness method, https://docs.python.org/2/library/stdtypes.html#truth-value-testing , which uses __len__ and __nonzero__, although more complicated that a __truthy__ magic method, is a good idea to ensure that containers with 0 length are false, and that numerical things are false iff they are zero. (what if something has both __len__ and __nonzero__? should this be prohibited? i'm guessing in this case __len__ is used)

---

so do all "nodes" covertly belong to a "graph", or is this a special rooted tree thing?

---

dont wanna have to do:

d1 = d[x] d1[y] = z d[x] = d1

would rather just do

d[x][y] = z

---

issue to be resolved:

i say that i want the primary data structure to be 'graphs' not trees or lists but if you look at the way languages like eg lisp, nock, haskell have 'lists' as their data structure, they really mean nested (binary, in the case of Nock and maybe Lisp, depending on how you look at it) lists = (possibly binary) trees; and if you say they have trees, then really they are conflating the idea of a variable holding a 'tree', and a variable holding a location within a tree, eg

x = (B (D E))

can be thought of as the tree:

x = 
  a
 / \
B   c
   / \
  D   E
where the capitals are leaf nodes

but then you do things like assign the node 'c' to another variable, y = x[1] == (D E), what you are really doing is assigning y to the value: the subtree of 'a' which is rooted at 'c'. Now if everything is immutable and pure/non-pointery it doesnt matter that that subtree was originally part of a larger tree, but if there are pointers then it does.

so if this sort of thing is what we mean when we say that Oot variables will hold graph values, then we really just mean that the values will be nodes IN the graph, and that by traversing the graph starting at these nodes, we can reach the rest of the graph. Which means that either (a) the nodes can really only be said to hold connected components, not any graph, OR (b) starting from any node, you can 'traverse' to some graph meta-node from which you can get to the entire graph, even if there are some nodes which are not reachable from the node you started with. I had been thinking (b) before, but now i'm wondering if perhaps the simplicity achieved in eg Nock is partly due to conflating nodes and their subtrees, which would suggest that (a) may be the better choice. If we do (a) then really what we're adding when we say we have 'graphs' instead of just 'trees' or 'lists' is (a) a way to make a node have multiple parents, (b) a way to make cycles, (c) built-in handling for edge types, including multiple edge directions, which then lets you traverse 'upstream' from a given node to its parent(s), (d) library functions that think in terms of graphs and (e) the other stuff such as labels, labeled boundaries, reification, etc. If this is the sorta thing we mean, then our 'graphs' are really quite similar to trees, except for the cycles; at first it may seem that being able to go 'upstream' from a node to its parents is really different, but if you just think of all edges as 'downstream' with attached metadata that lets us pretend that some are 'upstream' then (except for cycles) we really just have rooted trees, where going from a parent node to its child isn't allowed, but instead you just re-root the tree at the child.

if we did it that way, then since a given node could only really be said to hold a connected component, then library functions which want to actually operate on graphs (either because they need to deal with multiple disconnected components, or because it is more efficient for them to iterate over a list of nodes instead of traversing the graph starting from one node) would have to explicitly use an abstraction where the value of the node passed in was actually a 'metarootnode' which was a dict mapping node IDs to the nodes (in (b) i had been proposing implicitly using this abstraction everywhere, but now i'm questioning whether it might be cleaner not to). This would cause a fissure between those library functions which expect as input an ordinary node, and those library functions which expect as input a 'metarootnode'. Can Views smooth over this fissure, perhaps by providing something like database cursors, so that one view was of the entire graph, and another view acted like the value was actually one node within the graph?

so, there is a choice to be made between (a) and (b). To summarize, the issue is that, when we say that the data structure are 'graphs', do we mean that the value of a data structure directly represents an entire graph, or do we mean this in the same way that the values in Nock are binary trees, namely, that really the values are the root nodes OF a binary tree, and some library functions choose to interpret this as the binary tree itself? If the value of the data structure really directly represents the entire graph, then there are these metarootnodes all over the place, but otherwise, there are no metarootnodes in most places, but there are some metarootnodes required by some library functions.

i guess so far i like the idea of representing the entire graph and using views with 'cursors' to make it work as if you are representing a node within the graph most of the time

---

toread: https://www.gnu.org/software/guile/docs/master/guile.html/Fluids-and-Dynamic-States.html#Fluids-and-Dynamic-States

ok read that. i think Fluids are great! they appear to be a clean generalization of exactly what i was talking about with 'semiglobals'! to get a semiglobal in Guile Scheme, use 'with-fluids'.

also i think i understand 'dynamic wind' now, wind/unwind is like Python 'with', but note that it is also called in case of 're-entry' due to invoking a continuation.

---

only nil (including the nil-ish form of Option types) and False should be falsy, like Lua

---

so what does &object mean? some things:

---

Bel has "Dynamic bindings take precendence over lexical bindings, which take precedence over global ones."

makes sense. We should probably do that.

---