• No results found

A complicated structure representing various tables does not arrive fully formed: the user of a lish editor will want to build it incrementally, and subsequently modify it to respond to changing requirements or to correct errors. I therefore define some operations that may be carried out upon lishes.

4.6.1 Ordinary list operations

Since all lishes are lists, many of the textbook operations defined upon lists may be carried over. Some of these operations must be constrained, however, to ensure that the result is still a lish. Other operations on ordinary lists if applied unaltered to a lish would typically produce a non-lish result, but can be generalised to provide a lish-specialised version.

Standard list operations that query a list, but do not modify it, are unproblematic for the lish. We can ask the length of a lish, retrieve the element at a given index, and enquire whether a given element is an atom. Modifying the value of a single atom is also safe upon any lish, since this cannot alter the structure of any template, and hence whether any other elements conform to that template.

Creating a new root lish is almost the same as for an ordinary list, with one small change. Traditionally, a newly minted list is empty. That would not be allowed for the lish, so the “create new lish” operation returns a lish containing a single null: [•].

Before defining some further operations, I shall require one new piece of terminology.

4.6.2 The archetype of a lish

I have so far defined archetypes (subsection 4.3.1) only on traces, and conse- quentially upon those templates that are traces. I now extend the definition to a lish:

The archetype of a lish is the archetype of its posterior template. It follows from subsection 4.4.3 that the archetype of a lish whose prior template is an atom is the object id of the lish itself. Otherwise, it will be the same as the archetype of the prior template.

For example, referring back to the lish L of subsection 4.5.5:     0x0608  0x0600 [0x0500 1, 2], [0x0540 3, 4] ,  0x0640 [0x0580 5, 6], [0x05c0 7, 8]     

All four inner sublists have archetype 0x0500, which is the same as the object id of the first such sublist, containing [1, 2]. The two mid-level sublists each have archetype 0x0600, which is the object id of the first of those – the one containing [[1, 2], [3, 4]]. Finally the root lish has archetype 0x0608, which is its own object id. So the archetype is in each case the object id of the first in a series of lishes, which establishes a length that some further lishes later on must match (except for the root, which can have no related lishes outside of itself).

The archetype is the key to specialising certain ordinary list operations for the lish, since lish constraints can be preserved by ensuring that those sublists that share a common archetype are operated on consistently.

4.6.3 Specialising for the lish

I now take four operations that can be defined on ordinary lists, and spe- cialise them for use with lishes. The operations are:

insert. Given a list L and an index i, insert a null element at L[i]. For example, with i = 2:

[5, 6, [7], 8] ⇒ [5, 6, •, [7], 8]

delete. Given a list L and an index i, delete the element at L[i]. For example, with i = 2:

[5, 6, [7], 8] ⇒ [5, 6, 8]

enclose. Given a list L and an index i, increase by one the level of nesting at element L[i]. For example, with i = 2:

[5, 6, [7], 8] ⇒ [5, 6, [[7]], 8] Or with i = 1:

[5, 6, [7], 8] ⇒ [5, [6], [7], 8]

disclose. Given a list L and an index i, decrease by one the level of nesting at element L[i]. It is an error if that element is an atom. For example, with i = 2:

[5, 6, [7], 8] ⇒ [5, 6, 7, 8] In each case, an i that is out-of-bounds is an error.

The specialisation for lishes is in essence very simple: whenever one of the four operations above is invoked upon a lish with archetype A, it is implicitly invoked also upon every other lish that shares archetype A. There are however some additional requirements to ensure that the result of the operation remains a lish:

1. Insertion or deletion at index 0 is potentially problematic, because re- placing the head of a lish can have far-reaching effects upon templates downstream. Currently, I side-step this issue by requiring i > 0 for these two operations; this also removes any possibility of shrinking a lish to zero length. It would be desirable in future work to relax this restriction provided the result remained a lish.

2. For the insert operation, the newly inserted item must of course con- form to its prior template. The example just given specialises for the lish unchanged: the prior template is atomic, so a null is still inserted. More generally, the inserted item is a lish having identical structure to the prior template but all its atoms set to null.

3. When a sublist L[i] is enclosed or disclosed, it is actually those sublists sharing a common archetype with L[i], rather than the ith elements of those sublists sharing a common archetype with L itself, that must be likewise enclosed or disclosed.

4. A similar variation applies when the L[i] to be enclosed is an atom. This creates a new archetype equal to the object id of the newly cre- ated list. The other items to be enclosed are those whose prior tem- plate has now acquired this new archetype.

5. Disclosing a sublist that contains more than one element might in some cases produce a result that is not a lish. To avoid this problem I currently require the sublist to have only one element (which might be an inner sublist) before it can be disclosed. Once again, a future version of the lish might be more flexible provided the result remains a lish.

4.6.4 Some examples

Let us continue with the example of subsection 4.6.2, which (omitting the object ids) can be represented as:

"

[1, 2], [3, 4] , 

[5, 6], [7, 8]  #

We found in subsection 4.6.2 that the four innermost sublists share a common archetype, and the two mid-level sublists (the rows, as laid out above) share a different common archetype.

If we insert an item between 3 and 4, then the other three sublists sharing the archetype of [3, 4] acquire a similar insertion:

"

[1, •, 2], [3, •, 4] , 

[5, •, 6], [7, •, 8]  #

If we now insert an item between the two “rows”, we find that its prior template (omitting the archetype annotations) is

((1, •, 2), (3, •, 4)).

Constructing the new item to match this template, we obtain:      [1, •, 2], [3, •, 4] ,  [•, •, •], [•, •, •] ,  [5, •, 6], [7, •, 8]     

Now if we enclose the atom, 4, we create a new archetype. The posterior template of the first “row” becomes

((1, •, 2), (3, •, (4))).

Constructing prior templates for the remaining sublists, we find for example that 8 has acquired this new archetype in its prior template and hence needs to be enclosed, but 6 does not. We obtain:

     [1, •, 2], [3, •, [4]] ,  [•, •, •], [•, •, [•]] ,  [5, •, 6], [7, •, [8]]     

Three sublists, namely [4], [•] and [8], now share this new archetype; so if we disclose one of them, the other two must also be disclosed. Suppose we have done that, hence reverting to the previous state. Now let us enclose [1, •, 2]. This is already a sublist, so the other elements to be enclosed are those sublists that share its archetype. We obtain:

     [[1, •, 2]], [[3, •, 4]] ,  [[•, •, •]], [[•, •, •]] ,  [[5, •, 6]], [[7, •, 8]]     