Dictionaries

Dictionaries are probably the most novel concept in TinyAPL to date. I've long claimed an intent to make this APL dialect/derivative an experimentation playground for primitives and features, but many features are just aggregates from other array languages and the few new things are either trivial or at most not groundbreaking at all. Everything changes now.

Dictionaries are a new kind of array. They're not scalars, like structs or wraps, they're affine to arrays. Dictionaries and arrays are collectively called nouns(1). There are some other differences between dictionaries and structs as well: structs are mutable while dictionaries are not; structs' "keys" are identifiers and their "values" can be arrays (nouns), functions or modifiers, dictionaries' keys and values are both scalars.

The easiest way to create a dictionary is via literal. Dictionary literals look like this: key1: val1 key2: val2. To get an empty dictionary you can either use : or the primitive  Empty Dictionary.

The fact that dictionaries are nouns and not scalars means that most of the array operations you expect to work on normal arrays work on dictionaries as well, with some caveats and differences. Dictionaries act sometimes like a vector of pairs and sometimes like a ⟨n⋄2⟩ matrix. For example,  Major Cells is extended to work on dictionaries as Key-Value Pairs and returns a list of pairs and  Transpose is extended to work on dictionaries as  Inverted Table and returns an "inverted table", i.e. a pair of vector of keys and vector of values. Other primitives act in ways tailored specifically to dictionaries, for example  Index selects one entry by key (boxing it implicitly) and  From selects multiple entries by keys.

Literals don't allow you to create dictionaries programmatically. To do that, two glyphs and four functions were added:

Another common operation is combining two dictionaries. There are two primitives that allow you to do this:  Union and  Catenate. The difference is in the bias: the former prefers entries from the left argument when a key appears in both, the latter prefers entries from the right argument. The choice was made since  Union is in some sense left-biased for arrays, and  Catenate was the natural choice for the opposite operation. Other set operations work on dictionaries too, with the same left-bias (the set operations work on keys).

The last thing you can do to dictionaries is applying scalar functions to them. Scalar monads apply to each value of the dictionary and scalar dyads apply to values where the key appears in both arguments:

      ⟨'a': 1 ⋄ 'b': 2⟩+⟨'a': 3 ⋄ 'c': 9⟩
⟨'a': 4 ⋄ 'b': 2 ⋄ 'c': 9⟩

This might not always be the preferred operation, especially for functions which could have an identity but don't because identities don't exist in TinyAPL(2). It is however the most natural choice given the constraints of the language as it currently stands.

Dictionaries are of course ordered. They succeed all arrays and are then ordered by first sorting the keys, and then doing lexicographical comparison on the pairs. However for all purposes other than ordering, the entries of a dictionary are to be considered unordered.

Footnotes

  1. At least in the current implementation, the name isn't completely settled yet.

  2. Yet?