proj-oot-ootViewThoughts

E.g. if you are trying to add 1 to each negate each item in a list, you want to do:

l[i] = -l[i]

not:

if l[i] == F: l[i] = T if l[i] == T: l[i] = F

or, worse:

x = l[i] del l[i] if x == F: l.insert(i,T) if x == T: l.insert(i,F)

because in the latter cases, whatever metadata was attached to the original data before it was projected into a list of bools to be passed to you has been lost

otoh people want to use case statements. so maybe we just need an operator to tell Oot that although it looks like we're replacing instead of mutating, that it should count it as a mutation:

x = l[i] if l[i] == F: l[i] = T@x if l[i] == T: l[i] = F@x

x = l[i] del l[i] if x == F: l.insert(i,T@x) if x == T: l.insert(i,F@x)

note that sometimes you'll want to split or merge nodes, too:

x = l[i] y = l[i+1] del l[i] del l[i+1] l.insert(i,(x+y)@(x@+y))

x = l[i] del l[i] if x == F: l.insert(i,T@x) if x == T: l.insert(i,F@x) l.insert(i,F@x)

in these cases, '@' can be read as 'from'. Graphically, it's like a reference, that is, an arrow from one node in the code (here representing a variable) to another.

note that this has to do with lifting, e.g. inverting a homomorphism (or arbitrary function?) to find the inverse image of a node, and also with the 'lineage' of a node thru that homomorphism

--

Need to make sure that the connections between inputs and outputs of the function, and constraints on that, that is used for views, is fully general and is not restricted to only ancestry

Note that this helps with laziness too

---

note that the term 'view' is inconsistent with common usage, e.g. database views

---

Oot perspectives could be implemented by *monads*

---

the Spreadsheet stuff is similar to Oot perspectives in that both are related to binding, e.g. binding between DOM and UI in JS frameworks

--

we say we want to be mostly-referentially-transparent, but views are like aliased-variables/pass-by-reference/pointers/bindings-between-variables. So what gives?

actually i think these things are separable. As long as the view is only being used in a subroutine call, and the original is only being used in the caller, and the caller is blocking on the completion of the subroutine, then there is no problem. this is uniqueness typing.

even if the caller is not blocking to wait on the completion of the subroutine (an async call, like a goroutine), we're fine as long as the caller is not accessing the variable with a view until the subroutine is done.

and even if it does, we control/(track this binding in the type system) using the same mechanisms as an aliased/shared variable without views.

so these concerns are separable.

--

oot views are like generalized slices in l-values, or like the way that numpy maintains slices as separate but bound objects (except that, as above, views and aliasing are orthogonal in oot)

--

i guess views are different from the binding stuff i talked about with Doug in that, if you restrict them to shape-based correspondences/transformations, rather than dynamic formulas for computing (parts of) one view based on another, they become more constrained (and algebraicly tractable)

so, i guess i think they should be restricted in that way. binding (stuff like Trellis) can be a different thing (unless it turns out to make it simpler from a syntactical point of view to unify these things into one construct).

--

Why not just use multiple objects with internal links to each other via pointers? In a sense, this is all that views are; but because we encourage purity and frown on aliasing, we want to clearly label those objects which are connected to each other via pointers. Like monads in Haskell providing an officially-sanctioned (and clearly-labeled) escape from purity, in Oot views provide an officially-sanctioned (and clearly-labeled) way to 'break the rules' that discourage aliasing.

Why not just use multiple inheritance? Because a given object might fulfill an interface in multiple ways. For example, a Python dictionary could be viewed as a list of pairs (key, value), or a list of pairs (value, key), or it could be projected to a list of keys, or to a list of values. You may want to interate through the list of keys, apply a filter, and then end up with a dictionary in which those keys which you filtered out have been removed. This is the sort of thing that you can do with views. You could use 'multiple inheritance' to make a dictionary also behave as a list, but then is it a list of (key, value) or of (value, key) or of keys or of values? You would only be able to choose one. Or you could provide accessor functions getListOfKeysLinkedToThisDict(), but then you have separate objects internally linked via pointers; we'd prefer language support for a clearly-labeled and readable way to keep track of which objects are linked in this way.

---

---

consider 'fmap'; a function that takes two arguments, a container and a function, and applies the function to everything in the (flattened) container. The container must support an interface, call it 'fmappable' or 'flattenable' (depending on how it works) that knows how to flatten it.

But what if there are two implementations of this interface for a given data type? Eg for a binary tree you could say, fmap applied to a node could either apply the function to each of its descendent nodes, or only to its descendent leaf nodes (a third alternative could be to apply it only to the immediate children, not all descendents, eg fmap would be the same as map in this one). This is the 'coherence'-related problem in Haskell. In Oot we want to be able to implement the same interface in different ways on the same datatype, eg 'add' on an integer could be standard integer arithmetic or modular arithmetic; integers could be compared in the usual way, or by the subset relation on their prime factors; etc.

One could resolve this via Views. Eg one View of a binary tree type would use the fmap interface that applies to only the leaf nodes, while another View of the same binary tree type would use the fmal interface that applies to all interior nodes.

One could even define a View as an assignment of various concrete implementations to various interfaces (although i guess it is also a type; but what is a type but a set of interfaces that must be supported? well, i guess a type is also (a) a set of values, and (b) an algebraic thingee, eg the 'list' type constructor applies to the 'Int' type to produce list of Ints).

---