K is like APL with fewer built-ins. The syntax is ASCII-only, and most built-in functions are heavily overloaded single bytes of ASCII punctuation.
There are several implementations with subtly varying behavior. code.golf uses ngn/k, which is documented with the reference card found under "help" at the online interpreter. If you're new to K (and J, APL, etc...), this style of documentation might not be very helpful, but other learning material is available:
- Razetime has put together an extensive tutorial which introduces the language in multiple chapters, and then spends some time on solving larger tasks (including a Sudoku solver!).
- If you're looking for something in between the ref-card and a full blown tutorial, Stefan Kruger's kbook might be a good a fit.
- Another implementation of a similar K version is oK which comes with a more extensive manual
Example
Let's look at a program that outputs all of the input arguments with their length appended to them: `0:{x,$#x}'x
(Try it on United States: it outputs Nebraska8 Rhode Island12…)
`0:{x,$#x}'x
x Get the list of inputs.
{ }' Apply some lambda function to each input.
({} makes a lambda, and the adverb ' means each.)
x x Inside a monad lambda, "x" refers to the single argument.
# Monad # means "length"
$ Monad $ means "convert to string"
, Dyad , means "concatenate"
`0: Output the list of strings line by line.
0: is a dyadic writing-lines-to-a-file verb,
and the left argument ` (the empty symbol) means "write to STDOUT".
You can see that K is essentially read and written "right-to-left", much like J and APL. x,$#x means (x,($(#x))). There's no operator precedence.
Golf tips
\preceded by a space is "trace" (an identity function for debugging that prints its argument to STDOUT). This can be shorter than using`0:. Trace however passes its argument through the K formatter before printing, so this may only be useful for numbers.$[x;T;F]can becomex{T}/Fwhenxis a non-negative integer, or(F;T)xifxis 0/1 and lazy evaluation is not needed.xin the global scope is a list of the command line args.- Folds can take an optional left argument to use as a seed value. This can often save a byte:
1-+/x→1-/x,"1.",,/$x→"1.",/$x, ... - Calling primitives with brackets can sometimes save a byte on parentheses:
((A)+B),C->+[A;B],C(assume A, B and C are longer expressions). - Strings are sequences of (signed) bytes and can be used in place of a list of small integers in many cases.
- Each type has its own null value which indicates a missing value, for example not found in the result of find, or out-of-bounds indexing:
| Type | Null | Meaning |
|---|---|---|
| int | 0N |
$-2^{63}$ |
| float | 0n |
NaN |
| char | " " |
space |
| function | :: |
identity function |
| symbols | ` |
empty symbol |
Base Conversion
These come up a lot, almost in every other problem. A few ideas can be found on the APL tips and J tips page on StackExchange, so here is a quick translation table:
| K | J | APL | |
|---|---|---|---|
| Convert from base | / |
#. |
⊥ |
| Convert to base | \ |
#: or #.inv |
⊤ or ⊥⍣¯1 |
n\combined with strings is very effective at compressing sequences of integers. Example:
28+,/4\">>/" / days in a month (the string is `c$62 11 62 47)
0/xgets the last value ofx. Compared to*|x, it can be combined with other adverbs, e.g.0/'(last of each), and it returns0instead of0Nfor an emptyx.n/"..."is a good starting point for a string hash.
Undocumented Features
The reference card included with ngn/K skips on a few later additions to the language.
Case
This overload of ' combines multiple vectors using a selection list. The operand is a list of integers in $[0,n)$, the derived function takes $n$ lists of the same length. For each index, Case picks a value from the list specified by the selection. This function is taken from K4, see the KX documentation.
0 2 1 1 0'["ABCDE"; "abcde"; "01234"]
"A1cdE"
/ with n=2 case can be called infix:
0 1 2 3 4(0 0 1 1 1)'100 101 102 103 104
0 1 102 103 104
Recurrence
An extension to \ and / (both n-do and while). Instead of operating on just the last value, an operand function with $n$ arguments accesses the $n$ previous values. Instead of passing a single seed value, you'll have to pass $n$ seed values. As an example, we use a recurrence relation to compute triangular numbers:
$$ T_n = 3T_{n-1}-3T_{n-2}+T_{n-3} \qquad T_0=0, T_1=1, T_2=3. $$
/ T_0 to T_10
{(3*z-y)+x}\[10;0;1;3]
0 1 3 6 10 15 21 28 36 45 55
/ first triangular number larger than 1000
{(3*z-y)+x}/[~1000<;0;1;3]
1035
Internal Functions
0: and 1: are used for input and output, and 2: for loading shared libraries. But 3: to 5: can also be called, even though they are intended to be internal representation of combinations the interpreter automatically optimizes.
3:gets the last value, equivalent to*|:4:finds the index of the minimum (*<:)5:finds the index of the maximum (*>:)
Using these over the two-primitive combinations saves bytes if you combine them with adverbs, e.g. 4:'x, 5:/x, ...
.x
Monadic . does something for all types, not everything documented. I'd recommend just trying it for different inputs to see what happens. Relevant for golfing could be (.x) ~ x for numbers and simple lists of numbers, and (.x) ~ (*x).1_x for nested and mixed type lists.
External resources
- Matrix chat room specifically for ngn/k,
- The APL Farm has a room for K discussion,
- The K tree, a StackExchange chatroom about K. (inactive)
- Tips for golfing in K,
- A gist implementing the arithmetic operations required to solve the constant holes.