proj-oot-ootViewNotes1

earlier, i thought that perhaps views should be restricted to algebraic/shape-based mappings between structures, plus constants.

but now i'm wondering if perhaps we should make them a little more powerful than that. Perhaps allow computation (functions) within views (ie view transformation functions the perceive values within the data, not just its shape), but give them the same restrictions that Trellis computable, observable values have; namely, they must be "non-circular, side-effect free, and cannot depend on the attribute's previous value" (i would add deterministic, so that deterministic+side-effect-free = pure) (i'm guessing non-circular+cannot-depend-on-self means not recursive, and not mutually recursive with other such things, either) (and i'm guessing they can't call anything which does not meet these criteria, either). So i might say instead, "non-recursive, pure functions", or, a little more restrictive, "pure, primitive recursive functions".

hmm.. actually, what's important here is not that the function itself is primitive recursive or even terminating, but rather its interaction with the spreadsheet/trellis system, with rollbacks, epochs, memoization, idempotency, fixpoints, and the like. To be more specific, Trellis probably wants to be able to just update all of the computed functions a finite number of times (to propage the dependencies through the DAG; non-circularity is one of the conditions, remember), and then to know that even if it ran another update cycle, none of them would change (ie they have reached a fixpoint, eg the operation of running the necessary number of update cycles (the longest path in the graph) (call this one mega-update cycle) is idempotent, because there is no circular dependencies); it only has to run one computed function megaupdate cycle for every event (which i guess corresponds to one epoch in Glitch's paradigm); also, it knows that, being side-effect free and not circularly dependent, i bet computed functions aren't allowed to cause rollbacks, although i'm not sure about that.

And if they were pure, you could memoize their results.

in Oot, for view transform functions, we might want not only purity and non-circularity, but also non-dependence on any information outside of the variable for which this is a view (i guess that's a form of purity, but to be specific, it CAN depend on other information in the state of the 'object' for which a view transformation is being computed, but not upon other objects).

furthermore, we might identify an 'object' with the state domain accessible by view transformations on that object; we might require that, with the view transform functions, we can treat the object that the view transform functions is operating on as stored entirely on one local node or another as a threadlocal (so no need to worry about contention from other threads in the middle of this, atomicity, network failures/timeouts).

so, with all these restrictions, perhaps we can have view transform functions without having a fallible and complicated view-handling system. Something along the lines of lazily recomputing attributes upon request, with the addition of some dirty-marking code that says which view was the last view in which each attribute was changed, to resolve the inherent circularity of an object in which each view is defined in terms of the others (e.g. farenheit vs. celsius views).

---

hmm, in contrast to the above, mb no computation in views, afterall; want locality

but otoh we do want to expose different APIs over the same data, e.g. an array API with a .len function, and a dict API with a .keys() function. Aren't those functions essentially getting to do arbitrary computation anyways? And since we are unifying functions and table lookup, a dict with a .keys() function is no different from a table with a dynamically computed 'keys' attribute, in a sense.

---

could just fix one view to be the 'representation', ie the way data is actually stored

so then we don't allow collections of views with no all-encompassing view (a view that projects onto every other view, and is not projected onto (except isomorphically) from any other view). or rather, maybe we have a simple 'view addition' operator that takes any set of views, and constructs an all-encompassing view for them.

---

remember that a key part of views is to allow the transparent attachment/linking of meta-data or 'overlays' to other data structures

---

one use case of views should be to handle order statuses in an app like atr. Atr has orders, which should be linked to their status, and also their status as ATR sees it should be linked to the status object provided by the platform; e.g. the broker IB might have an order status like Inactive, but ATR needs to additionally add statuses like 'new order, not yet sent to broker', and 'attempted to be sent to broker, but broker has not yet acknowledged'.

--

this also needs to make sense in the context of FRP, eg an 'order status changed' event from the broker needs to be linked to the 'order status changed' ATR framework event, and both need to be linked to the order object and to its status.

--

perhaps Views should also include a method of attaching/linking data to other data records stored externally. For example, in ATR, the broker IB might be tracking the status of an order, but not telling the client about it until the client queries it. So, our local information about the order includes the IB order identifier, but only the last known status, not the current status; or, if the order wasn't made by this client in this run, maybe we initially don't have any information at all besides the order's identifier. The order identifier is a sort of 'foreign key', but we should be able to attach views to the records accessible by this foreign key, even if we don't possess a copy of those records ourselves before querying.

--

perhaps we should have a sentinel for 'this information is stored externally, we can get it but only via a query'?

--

http://existentialtype.wordpress.com/2011/04/16/modules-matter-most/ says "There are two fundamental problems with type classes. The first is that they insist that a type can implement a type class in exactly one way. For example, according to the philosophy of type classes, the integers can be ordered in precisely one way (the usual ordering), but obviously there are many orderings (say, by divisibility) of interest. The second is that they confound two separate issues: specifying how a type implements a type class and specifying when such a specification should be used during type inference."

we need to make sure that Oot views provide a convenient way for ppl to represent, eg, the idea that integers can support the PartialOrder? interface in multiple ways, depending on whether the ordering is the natural one, or by divisibility, or whatever.

but also, we need to remember to provide a way for interchangable IMPLEMENTATION types

---

integers can be divided into equivalence classes in various ways. E.g. even vs. odd; negative vs. zero vs. 1 vs. prime vs. non-prime. Say you have an integer in variable x and another integer in variable y and you want to test if they are in the same equivalence class.

there various ways to deal with this:

this is related to my desire to have a good way to test whether some exception is e.g. a ClientException? or a ServerException?, the way that 'is' in English works, e.g. an instance of ClientSyntaxError? is a (isa) ClientException?, just as a dog is a mammal; but we might also say that a dog is blue, and that Bob is Bob, and that Venus is the Morning Star. In some contexts we may also want to conflate the difference between instance and subclass and structural equality, and to let one operator test for all of equality, isInstance, and isSubclass.

so far i like the flag-setting approach best. This can be unified with data views, in that we are simply asking for a view of x in which .__eq is the desired one, and the same for y. Note that:

we could have four kinds of equality: == (defined by the Eq typeclass instance assigned to this view; also, includes isInstance and isSubclass as 'is'?), === (structural equality (view-independent?)), ==== (pointer equality) hmm.. this 'is' stuff doesn't go well with typeclass redefinition of stuff, b/c ppl won't bother to do it right

is there a way to do scoped views too? e.g. "within this scope, == is given by the ==_odd_even instance"? again, even if we could do this, lexical or dynamic? and how would we determine which variables to bind these scoped views too ("within this scope, INTEGER == is given by ..."?)

---

---

often i describe one reason why views are needed is so that if a functional/immutable function needs to create a new copy of something of the same type of the input variable, with its metadata attached. traditional parametric polymorphism can handle creating a new copy of the same type, but it won't copy over the metadata.

---

probability could be thought of as an additional 'view' on values of truth state variable.

provenance could be thought of as another such view.

fact views could be called 'facets'; faceted classification?

---

indeed faceted classification is appropriate, and goes with what i was saying about wanting to consider integers in various ways, e.g. under the natural ordering, under ordering by divisibility, as an additive group vs. as a multiplicative group (and '-', the inverse operator, will have different effects there), in the equivalence classes of even vs. odd, i might add as a ring, etc. In faceted classification you can assign each objects to MULTIPLE separate hierarchies -- so e.g. a dog can be a mammal (which is a subclass of animal), but can also be a thing whose name is three letters (a subclass of things whose name is three letters or more, of which another example if 'mammal'). Note that two objects can both appear in various of these hierarchies, but with different relations. You might say that these hierarchies are orthogonal, and that a graph combining all of them would have 'colored edges', one color for each hierarchy.

---

how to organize all of these view facets?

---

could we do non-copying references into strings (in general, slices) as views? if so, we need to be able to have functions that dynamically generate views on the fly based on parameters, right?

---

maybe have Perl-like type sigils for common views? eg asArray?

mb have a 'len' (length) view and mutate it to preallocate? (mb #)?

---

y'know, i've been thinking about views as something where you actually pass around the full representation of a value, but then when you look at it you do indirection to see which view you are looking at, and then expose an interface to the object, but this is really just an implementation detail.

You can pass around any sort of value that has a 1-1 correspondence to the values of the full representation. For example, if you are using views like this:

1) say there are a type of object caled Cell (for memory cell). A Cell consists of a record (struct); this record says whether it is a symlink or contains its own value. If the cell stores its own value, that cell's record also contains a pointer to this value. 2) so if you are given a cell, you can access the cell's current value, or you can access this record 3) sometimes you want to pass around an array of cell values, where each value is not really just the value, but actually just a View of the Cell; eg if each cell holds a character, then this View makes the whole Cell act as if it were just the character 'contained' in this cell (or the character contained in the target of this Cell's symlink) 4) you could do this by passing around Cell objects that expose an interface that intercepts read and writes to the values in the Cells, and redirects them to the contents of the cells, as if the array holding the Cells were actually just an array of ordinary characters. But when you take a reference to what appears to be one of these ordinary characters, instead of getting the memory address of the Cell's contents, you actually get the Cell record, which pretends, via a View of a Cell, to be something like a pointer to this Cell's struct. If you possess this value, then you can switch to a different View of this to see the metadata in the record, such as the symlink, if you like. 5) alternately, you could give each Cell a unique identifier, perhaps an integer, and when you take a reference to one of these characters, you get an identifer. The runtime has a lookup table that maps ids to Cells. 6) the advantage of (5) is that if, perhaps you call some routine that sorts what it perceives to be the Cells' memory addresses. in the case of #4 it is sorting possibly huge structs, in the case of the latter it is sorting small primary keys.

Does this have bearing on my desire for explicit representation of when different things are identifiers for the same thing?

Also, how would this fit in, if at all, with this use of views?:

1. Take the view of dict which makes its keys looks like a mutable array 2. Pass this 'array' to a filter, have it delete some things 3. Now the relevant entries in the dict have been deleted

(also note here, do we really even want a 'mutable array'? i think we do, i think this is a prime example of how Views represent the only form of aliasing which is 'encouraged')

well, one thing it means, is that since the dict keys must be unique, it's an implementation decision whether to pass pairs (id, key) instead of just 'key' into the filter, and then rewrite the filter so that whenever it looks at these pairs, it only sees 'key', or alternately to trace into the filter and track deletions (one of the previous two options must be supported in the general case, for other views in which the things being deleted aren't unique), or alternately to just pass in the keys and afterwards look at which keys are left and reconstruct the array

---

another basic motivation of views is to have something like Haskell-style pattern matching (eg a List is either an EmptyList? or a Cons(a,l2) where l2 is a list), but while allowing the list of Constructors to change per-view

---

note: you can recover an alternate view from a value, provided that other view was assigned to a predecessor of the value within your scope or below it (or something like that)

eg if you start with a pair (x,y) of ints, and take a view that projects the first element of the pair, then you pass this into a function and get an int that results from it in return, then you can take a 'pair' view of that int to get back the y

---

as an aside, while i was reading https://en.wikibooks.org/wiki/Haskell/Applicative_Functors , i happened to see this:

" For technical reasons, we cannot define an Applicative instance for [], as it already has one defined. This instance does something completely different. fs <*> xs takes all functions from fs and applies them to all values in xs. To remedy this, we create a wrapper:

  newtype ZipList a = ZipList [a]
 
  instance Functor ZipList where
    fmap f (ZipList xs) = ZipList (map f xs)"

so is solving the Haskell typeclass namespacing issue the same thing we are doing with Oot Views?

--

in fact, maybe which implementation of an interface is chosen could be a function not only of the interface, but also of a 'context', which is akin the idea of a 'level' metaprogrammatically changing the meaning of a set of symbols.

---

speaking of my meta project, the meta levels as 'data, information, knowledge' (what was above that?) corresponds somewhat to typing:

but the main meta levels (hyper, meta, 3, ?) don't directly correspond to that.

---

the idea of 'views that can rearrange stuff across data object boundaries' may be novel (within these notes, at least). Imagine an 'Adaptor pattern' but applied to a set of related objects. This suggests that there is a larger object with a boundary containing all of these objects. In OOP, i guess that's a composition pattern (ie nothing fancy, just a bunch of smaller objects inside one larger one), and then an adaptor wrapped over that larger object. But what if things were more dynamic, and you could have multiple 'large containing objects' with disjoint ownership of other objects (and of each other).

---