https://beyondloom.com/blog/denial.html
Stages of Denial
It is a lazy Tuesday afternoon. Perhaps you were idly browsing your
favorite news aggregator, or visiting The Orange Website to wade
through murky startup groupthink in search of interesting links.
Today, though, you arrived at an enigma. A proprietary,
closed-source, commercial programming language. A bizarre
anachronism. The programs, if you can call them that, resemble the
results of a prolonged fistfight with a keyboard. The language is
simply called "K". You snort at the vulgar presumptuousness of a
single-letter name, before self-consciously averting your eyes from
the C compiler output in a nearby terminal.
One K example looks like this:
+/!100
Completely illegible. Fortunately, another soul has provided a
translation into something intuitive and natural:
int sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
}
There is no visible correspondence between the structure of these
programs. You discern no parts of speech in the K, no names to grasp
onto to extract meaning. Frustrating, and yet... intriguing. K seems to
be one of these "code golf" languages designed for writing cryptic
one-liners that minimize (key)strokes and demonstrate one's
cleverness. Who doesn't like to demonstrate their own cleverness?
Then you scowl and remember that clever code is impossible to
maintain.
Before a treatise can work its way out of your fingers on the value
of simple code which is comprehensible to even the most junior
Stanford-educated Google employee, (optimization being the root of
all evil, as you once read, paraphrased) someone else points out that
a more direct translation into another language might look like:
sum = range(100).reduce(plus, 0)
The correspondence is clearer now. If each punctuation character in
the K is a separate part of speech, and you reverse their order...
+ / ! 100
plus reduce range 100
Backwards! You stifle a chuckle. What next? Still dubious, but
increasingly invested in this puzzle, you spend some time reading
more about K. A few rogue lunatics have furnished mostly-working open
source interpreters for dialects of the language, so you give them a
try. You read a few essays and tutorials, flip through the manual for
K2 that serves as the primary comprehensive reference for the
language, and have a go at solving some Project Euler problems.
In the course of your reading you briefly encounter J and APL, which
seem even more alien than K, and yet... the same in many ways. J and
APL have K's right-to-left evaluation (in annoying defiance of PEMDAS
, for some reason), the / symbol means "reduce", and you can add 5 to
an entire matrix at once as easily as a single number. Why you would
want this property remains elusive- it seems rather academic and
mathy- but you can't help but admit that it's rather neat. You have a
growing impression that K is not simply a one-off oddity, but rather
a member of a whole family tree.
Fine, K has some appeal. Being able to dash off ,/ to flatten a list
is nice. The "grade" operators < and > seemed like a clumsy way to
sort at first, but you're starting to see that "permutation vectors"
have many other uses. There's something deeply right about how list
indexing and function application are the same operation. K seems too
domain-specific to use for real work, but maybe it would be handy to
implement some of the K primitives as a library for your favorite
language?
The symbols still feel like a problem. Wouldn't it be clearer and
more readable to simply use spelled-out names? Maybe instead of
writing:
*>#:'=
You could factor the definition apart and use more explicit syntax:
groupIndices: {[list]
: =list
}
countEach: {[dict]
: #:'dict
}
maxIndex: {[list]
: *>list
}
mostCommon: {[list]
: maxIndex[countEach[groupIndices[list]]]
}
In principle, this should be more readable and easier to understand.
You have dutifully broken down the definition into reusable parts and
given them clear, meaningful names, a best-practice that you learned
in your earliest programming courses and have carried forward
throughout your professional career. Still, this time there's
something worryingly unsatisfying about the results. The name
"mostCommon" is longer than the entire definition in K if you write
it more succinctly.
It is possible to write K as if it were a strange-looking Lisp,
M-Expressions and all:
fibs: {[n]
if[less[n;3];:iota[n]]
fibrec:{[list]
if[equal[n;count[list]];:list]
a:list[minus[count[list];1]]
b:list[minus[count[list];2]]
:_f[join[list;plus[a;b]]]
}
:fibrec[(0;1)]
}
Or you could express the same idea without conditionals, recursion,
or any explicitly named variables:
{x#x{x,+/-2#x}/0 1}
Does giving a K idiom a name make it clearer, or does it obscure what
is actually happening?
sum: +/
raze: ,/
ordinal: <<
The word "ordinal" can mean anything, but the composition << has
exactly one meaning. (That one took a while to click, but it was
satisfying when it did.) If the primitive "group" was just that word
to begin with, would you have known what it did any more than if you
saw the symbol =?
square: {[number] number*number}
square: {[n] n*n}
square: {x*x}
{x*x}
Sometimes a long name is more descriptive, but sometimes it's just...
longer.
You feel a perverse urge:
sum:0
i:0
while[i<100
sum+:i
i+:1
]
It's more explicit than +/!100, but now it leaves a bad taste in your
mouth.
Your old languages don't feel quite the same.
Reviewing a patch one of your coworkers submitted today, you
recognize a loop with a familiar structure:
let max = list[0];
for (let i = 0; i < list.length; i++) {
if (list[i] > max) { max = list[i]; }
}
You suggest an alternative, wincing slightly at the lambda notation
you need to avoid running afoul of JavaScript's variadic Math.max():
list.reduce((x,y)=>Math.max(x,y))
Your suggestion is rebuffed as cryptic and overly complex. Lambdas
are hard to understand, not to mention reduce(). A for loop is much
more intuitive, natural, and readable, it is argued. If you used
clever tricks everwhere in the codebase, it would be impossible to
maintain. A compromise is committed:
let max = list[0];
for (let i = 0; i < list.length; i++) {
max = Math.max(list[i], max);
}
On The Orange Website, someone has started a thread about an obscure
language with a single-letter name. Commenters are quick to express
incredulity at how unreadable it is.
Leaning back in your chair, you think to yourself:
|/
back