In an earlier post I described a special kind of list (actually, a special kind of multiset) that can be represented more efficiently with a structure like this:
dd = discreteData[<|"scale" -> 1.234,
"bias" -> 5.678,
"tally" -> {{-5, 2},
{-4, 251},
{-3, 5941},
{-2, 60383},
{-1, 241185},
{ 0, 383613},
{ 1, 241644},
{ 2, 61035},
{ 3, 5686},
{ 4, 259},
{ 5, 1}}|>];
(Basically, the values encoded by this data structure are all of the form $kS + B$, where $k$ is an integer, and $S$ and $B$ are the numbers that the data structure labels "scale"
and "bias"
. The "tally"
item is a list of pairs $\{k, n\}$, where $n$ is the number of times that the value $kS + B$ appears in the data.)
Now, let
dd2list[dd_] := dd[[1, "bias"]] + dd[[1, "scale"]] Flatten[ ConstantArray @@@ dd[[1, "tally"]] ];
Since any discreteData
object dd
contains the same information as the corresponding List
object dd2list[dd]
, it would be great if one could arrange matters such that dd
and dd2list[dd]
could be used interchangeably in Mathematica programs.
By defining suitable upvalues, one can have dd
behave like dd2list[dd]
in the specified context. E.g.
discreteData /: Length[ d_discreteData ] := With[
{ assoc = d[[1]] },
Plus @@ ( Last /@ assoc[["tally"]] )
];
Length[dd] == Length[dd2list[dd]]
(* True *)
Unfortunately, this one upvalue covers only a tiny fraction of the expressions one is likely to find dd
in. If one mistakenly replaces a list object with its discreteData
counterpart in an expression for which no proper upvalue has been defined, the results could change dramatically (and for the worse, of course).
For example, if dd
is defined as shown above, the evaluation of Sqrt /@ dd
succeeds without warning, and the result even has the correct "shape" (i.e. the right head, the right fields, with values also correctly dimensioned), but it is grossly incorrect.
Of course, one can avoid this one error by defining a suitable upvalue for Map
, but in order to make this data structure resistant to such silent errors in general, one would have to implement upvalues for a huge number of list-consuming functions. This does not seem practical to me.
In order to make such a data structure behave like a List safely, one needs at least one of
the specification of a complete list interface;
a way to make it a visible error to apply to objects of the new class any function that is not included in a white-list of approved functions.
(NB: the white-list mentioned in 2 consists of precisely those functions for which I have defined upvalues.)
Please correct me if I'm wrong, but, AFAIK, Mathematica has nothing like 1.
This leaves 2. Is there a way to implement this?
Clarification: option 2 will not solve the problem of making discreteData
behave like a list in any appropriate context; it only solves the problem of silent errors.
UpValues
but I think your whitelist will be necessarily huge. Perhaps even more than the list interface. $\endgroup$discreteData
objects safely. I think the silent errors I illustrated represent to big a risk. $\endgroup$