A K list Z
is usefully understood as the map from !#Z
to the values of Z
. M, a variant of K, is implemented in which the primitives ?
and !
are reinterpreted to operate on lists thus reconstrued[1].
K has atoms, lists, and dictionaries.
Lists are maps[2]. The list Z
of length n is a map from !#Z
to the values of Z
:
0 -> 10 1 -> 20 2 -> 30
We can use this insight to simplify K by reducing the number of ultimate entities, and therefore distinct ideas present in the language[3]. With fewer ideas the language becomes simpler and easier to learn. I call this variant of K "M". In the examples given below, execution in the M console is indicated by the presence of the prompt "m)".
K has atoms, lists, and dictionaries. M has atoms and maps. K dictionaries are M maps, and so are K lists.
In M a map is created using dyadic !
. The left argument is the domain and the right argument is the range:
m)a:`a`b`c!10 20 30 `a`b`c!10 20 30
The domain of a map is retrieved using monadic !
[4]:
m)!a `a`b`c
and the range using monadic ?
[5]:
m)?a 10 20 30
In M lists are also maps, and use the same constructor and deconstructor primitives:
m)b:0 1 2!20 30 40 20 30 40 m)!b 0 1 2 m)?b 20 30 40
The domain of a list can be elided. The constructor is applied automatically:
m)b~20 30 40 1b
Display of a list also elides the domain. The deconstructor is applied automatically:
m)b 10 20 30
The domain of a list is also a map, whose domain and range are identical.
m)m:!10 20 30 0 1 2 m)(!m)~?m 1bThe domain of a list is a fixed point of
!:
, so the predicate for listhood is[6]:
m)islist:{(!x)~!!x}
In M we use ,
to join maps:
m)1 2,3 4 5 1 2 3 4 5 m)(`a`b`c!10 20 30),`b`c!40 50 `a`b`c!10 40 50
Lists and dictionaries are both maps, but lists are not dictionaries. It would be wrong to insist on dictionary semantics for the concatenation of lists:
m)1 2,3 4 5 0 1 0 1 2!1 2 3 4 5
Structural operations in M are otherwise identical to those in K:
m)|10 20 30 30 20 10 m)|`a`b`c!10 20 30 `c`b`a!30 20 10
Dictionary-maps can "collapse" into list-maps:
m)0N_0N 0 1 2!10 20 30 40 20 30 40
and list-maps can "explode" into dictionary-maps:
m)((,0N)!,10),20 30 40 0N 0 1 2!10 20 30 40
Mapping list-maps therefore behaves differently in K and M[7]:
In K:
k)(0 1 2!10 20 30)!0 1 2!40 50 60 'type
In M:
m)(0 1 2!10 20 30)!0 1 2!40 50 60 10 20 30!40 50 60
The universe of M is therefore smaller than that of K. The list Z
is identical to the constructed map (!#Z)!Z
[8]:
m)10 20 30~0 1 2!10 20 30 1b
Concatenation of lists in M behaves differently than the concatenation of the homonymous dictionaries in K[9]:
m)(0 1!1 2),0 1 2!3 4 5 1 2 3 4 5 k)(0 1!1 2),0 1 2!3 4 5 0 1 2!3 4 5
Here are some analogies from elsewhere in K:
- In K, a mixed list can collapse to a vector, and a vector can explode to become a mixed list.
- In K4, a list of structurally identical maps is a table. To avoid the collapse from list-of-maps to table we add a "sentinel" -- a map with a different structure.
- In K2/3, where ^:
is the shape primitive, a list of equal length lists is a matrix or higher-order rectangular array.
The k4 script for M is:
\d .m e:{f@-6!g@-5!"k)",x} g:{$[0>t:@x;x;~t;.z.s'x;x~(!);map;x~(!:);dom;x~(?:);val;x~(,);cat;x]} f:{$[0>t:@x;x;~t;.z.s'x;99h=t;map[!x;.z.s'. x];x]} dom:{$[(t:@x)in 99h,- 1 4 5 6 7h;!x;~t<0;!#x;!x]} map:{$[x~!#y;y;x!y]} val:{$[(t:@x)in 99 10h,- 10 11h;. x;~t<0;x;. x]} cat:{dfl[x;y],dfl[y]x} dfl:{$[(99h=@y)&(98h>t)&~0>t:@x;(!#x)!x;x]} k)\
and is found here:
An example M script:
a:`a`b`c!10 20 30 !a ?a b:0 1 2!20 30 40 !b ?b b~20 30 40 !!10 20 30 1 2,3 4 5 (`a`b`c!10 20 30),`b`c!40 50 0N_0N 0 1 2!10 20 30 40 ((,0N)!,10),20 30 40 ((,0N)!,10),0 1 2!20 30 40 10 20 30~0 1 2!10 20 30
is found here:
Operate it this way:
q m.k \l m.m
M extends and overrides three K primitives: !
!:
and ?:
. We can merge the behavior of the two monads onto !:
, thus preserving the original K meaning for ?:
:
m)`a`b`c!10 20 30 `a`b`c!10 20 30 m)!`a`b`c!10 20 30 (`a`b`c;10 20 30)
!x
returns (domain x;range x).
The two-primitive version of M uses the following modified 'g' function:
g:{$[0>t:@x;x;~t;.z.s'x;x~(!);map;x~(!:);{(dom x;val x)};x~(,);cat;x]}
NB: m.m will fail with this definition in force.
The revised definition of !:
has a few nice properties. For example, where we want to pass the domain and range of a map to a dyadic function:
k) f[!x;x[]]
as against:
m) f .!x
and to swap domain and range:
m)(!).|!`x`y`z!10 20 30 10 20 30!`x`y`z
Z
is a list, !Z
is symbolic type.
Z
is a dictionary, ?Z
is a type error, and ?Z
is unique.
m)a:10 20 30 m)a~?:/a 1b m)a~?a 1b
!Z
and ?Z
are lists, they are also maps. M-maps are infinitely deep, infinitely wide trees.
X
and Y
are list-maps, there are no maps with dictionary-domain or dictionary-range. That is, even where (#X)=#Y
, if either X
or Y
is a dictionary, X!Y
is an error. Where X
is a list and Y
is a dictionary, X!Y
is a length error and Y!X
and Y!Y
are both type errors.