6.3.1 The 1:1 case
I now consider the converse of the situation in the previous section. Suppose we have completed a calculation, whose result is either a single number or a trace. We now need to write the result back into the lish. For example, in the previous section we might have calculated the row sums of the sales figures, and wish to write the answer (850, 600) back into the “Total” column.
In this example there is a convenient one-to-one correspondence between the cells in the answer and the inheritors of Total, which are currently both null. Writing the answer back consists simply of overwriting the two nulls with the two numeric values, and we obtain:
•, Sales summary,
Region, Sales, Jan, Feb, Mar , Total North, •, 200, 350, 300 , 850 South, •, 150, 200, 250 , 600
6.3.2 The n :1 case
What if we had carried out the same calculation, but wanted the result to be stored separately from the table, instead of in an existing column? If desired, we could create elsewhere a new sublist of three cells (one template- forming cell for the label, and two ordinary cells for the numbers) and write the result there instead. But this would impose upon the user the extra step of allocating the required number of new cells in a standalone list. And there is a more serious problem. The lish is intended to support a spreadsheet-like recalculation model, where the results of formulae are refreshed as necessary upon changes to the data. If the user were to set a formula for the row sums in a standalone sublist but subsequently inserted a row in the table, the standalone sublist (not sharing a common archetype with any part of the table) would not receive a corresponding insertion. The formula result upon re-evaluation would no longer fit.
The lish solves this problem by allowing a multicellular formula result to be written into a single cell – a form of dynamic memory allocation. The receiving cell is promoted to a sublist and the resulting structure can be navigated just like any other sublist. In that sense, it is indistinguishable from content that the user created explicitly. However it is marked internally as being dynamic so that the formula evaluator knows to revert it to a single cell prior to recalculation. Hence the new value will be unconstrained by the structure of the previous value. The dynamic marker is also consulted by the graphical rendering procedure (subsection 5.4.1), which draws a dotted border around dynamically generated regions.
6.3.3 The 1:n case
The converse of the previous situation occurs when the result of a calculation is a single cell, but the destination is multicellular. This is rather easier to deal with, as no new structure needs to be created. The single value is simply recycled over all the destination cells, making a copy in each one (and overwriting any existing content). A typical use case would be to fill an entire column with a uniform value.
6.3.4 The m:n case
In the most general case, we have m result cells to be written into n destina- tion cells, which might differ both in structure and in extent. One use case is when some dimensions of a structure are static, but others are dynamic.
For example, in the Sales table we might have had a situation where each region was explicitly created by the user, giving a static number of rows, but the monthly data were the result of a formula where the number of months to include was not known in advance. I now give a general procedure for the m : n case.
The sub-cases where either the result or the destination is a single cell are handled as above, so I assume here that the result is in the form of a trace, T . Likewise I construct a second trace, U , formed from the destination cell and all its inheritors according to the procedure of section 6.2. In this context, the trace U is formed by reference, so that mutating an element of U is the same as mutating the corresponding element in the receiving lish.
If U is of length one, it is first dynamically expanded to match the length of T , if that is greater than one. For example, if T = (Var1, 1, 2, 3) and U = (Var2) then U is expanded to (Var2, •, •, •) before any further operations are applied.
There are now three sub-cases to consider, depending on the length of T . For all sub-cases, the first cell contained within U , which typically contains the label for the result, is specially exempted and is not overwritten. (In the event of a recursive application of the procedure, this exemption is applied only at the outermost level.)
Sub-case 1: T is of length greater than two
We first compare the length of T with the length of U (after the above expansion, if applicable). If the two lengths are equal, each element of T is written into the corresponding element of U , with recursive use of the current procedure. Otherwise, U is filled with an error indicator, “Err!”, to signify to the user that the result of a calculation could not be matched to the structure intended to contain it.
For example, if T = (Var1, 1, 2, 3) and U = (Var2, 4, 5, 6) we obtain (Var2, 1, 2, 3). But if U were instead the longer trace (Var2, 4, 5, 6, 7) we would obtain the error-filled result (Var2, Err!, Err!, Err!, Err!). Recall that the first cell in the destination is exempted from overwriting, so Var2 appears in the result in both cases.
Sub-case 2: T is of length equal to two
In this sub-case, the first element of T is written into the first element of U . The sole remaining element of T is recycled over every element of U except
the first. This supports a pattern where a scalar value is represented in a lish of two elements, where the first is a label and the second gives the value. For example, if T = (pi, 3.14) and U = (pi column, •, •, •) then we obtain (pi column, 3.14, 3.14, 3.14).
Sub-case 3: T is of length one
In this sub-case, the sole element of T is written into every element of U . For example, if T = (3) and U = (Answer, 4, 5, (6, 7)) then on writing T into U we obtain (Answer, 3, 3, (3, 3)). In this example, the 1 : n case was applied when it came to writing 3 into the sublist (6, 7).
6.3.5 The m:n procedure in action
The procedure above accommodates cases where some of the structure in the result was already present in U , but further structure was contributed by T . For example, with T = (•, 1, 2, (3, 4, 5), 6) and U = (Var1, 7, 8, 9, 10), we would obtain (Var1, 1, 2, (3, 4, 5), 6). In this result, the sublist (3, 4, 5) replaced the single cell 9 in the original.
New structure can also appear as a result of a U of length one being expanded. For example, suppose we have:
T = ( •, Var1, Var2 ), ( •, 1, 2 ), ( •, 3, 4 ), ( •, 5, 6 ) , U =( Results, •, • )
Since T is of length four but U is only of length one (it contains one sublist of three), U is first expanded to length four. In accordance with the lish insertion operation of subsection 4.6.3, each of the three new elements conforms with the prior template established by the first, and we obtain:
U = ( Results, •, • ), ( •, •, • ), ( •, •, • ), ( •, •, • )
the content of T has been copied over we obtain: U =
( Results, Var1, Var2 ),
( •, 1, 2 ), ( •, 3, 4 ), ( •, 5, 6 )
The end result is a table that always has three columns, as determined by the original structure of U, but may have any number of rows depending on how many there are in T . If T were to contain more than three columns, U would be flooded with error indicators.