Introduction

This is an introduction to the Kap programming language.

About Kap

Kap is a programming language where most programs are executed directly on the REPL, as opposed to being typed into a file and run. The goal is to allow the user to easily perform computations without having to write a full program, with all the extra work that entails.

The best comparison is with the Unix shell. While a shell like Bash is a full programming language, the majority of Bash code are commands written by the user at the prompt. Sometimes these commands can be quite complex, and solve very complicated problems. And once the command is typed, the code is no longer needed, so it scrolls off the screen (perhaps accessible in the command history).

Kap aims for a similar type of usage. The language is so concise and powerful that it allows users to solve, directly in the REPL, problems that would require tens, if not hundreds of lines of code in other languages.

However, Kap is not magic, and it requires the user to approach problems in a different way, thinking about data in terms of arrays with a shape that operations are performed on, rather that sequences to be iterated over. It can be both challenging and fun, and it can be worth the effort to learn the language.

Please visit the Matrix room where any questions about the language and how it’s used will be happily answered.

To provide feedback on this tutorial, either go to the Matrix room, or report an issue on Codeberg.

About the tutorial

In the examples below, input is indented by 4 spaces, and output immediately following the input:

    This is the input
This is the output

At the REPL, after executing an expression, the return value is printed in a way that is useful for human consumption.

Kap uses non-ASCII characters for some operations. When introduced, the keys to type to obtain these symbols are stated in the text.

The easiest way to follow along is to use the web-based REPL, which is implemented in Javascript. Other versions are available on the download site.

Syntactic elements

Numbers

Numbers return themselves:

    1234
1234
    0
0
    10000000000000000000000000000000000000000
10000000000000000000000000000000000000000

From the last example, we can see that there is no limitation to the size of an integer. Internally, integers that fit in 64 bits will be stored as such, while larger numbers use bigints. This is completely transparent to the user, except for performance differences.

Negative numbers use ¯ (input: `, 2). This is to distinguish it from - which is a regular function.

    ¯1234
-1234

Note that the ¯ symbol is part of the number, and not a function. Note the difference between the following two expressions. In the first case, the two numbers negative-1 and 2 form an array. In the latter case, the two numbers 1 and 2 form an array which is passed to the function - which negates the members.

    ¯1 2
-1 2
    -1 2
-1 -2

When printed, negative numbers are displayed using -, since this makes it more convenient when copy&pasting to other tools.

If a number contains a ., it’s a floating point number. These follow standard IEEE-754 64-bit semantics:

    1.2345
1.2345
    12.0
12.0
    0.0
0.0
    1000000000000000000000000000000000000000.0
1e+40
    typeof 0
kap:integer
    typeof 0.0
kap:float

From the above, we can see that 0 and 0.0 are two different numbers, one being an integer and the other a floating point number.

Rational numbers are given by separating the numerator and denominator using the character r:

    1r10
1/10
    typeof 1r10
kap:rational

Integers are also rational numbers, and dividing two rational numbers will yield a rational. This avoids a lot of precision problems inherent in the use of floating point, at the cost of performance. It is always possible to force the use of floating point calculations by using floating point numbers instead of rationals.

Complex numbers are specified using the letter j between the real and imaginary parts:

    1j4
1.0J4.0
    typeof 1j4
kap:complex

Characters

Characters are 32-bit Unicode codepoints and specified using @, followed by the character, or a backslash and a code description as follows:

  • @a — Any character is allowed, except backslash

  • @\LATIN_CAPTIAL_LETTER_B — Unicode name, spaces are replaced with underscore

  • @\u0397 — Hex codepoint

  • @\n — Newline (codepoint U+000A)

  • @\s — Space (this exists because @ followed by a space is very confusing)

Examples:

    @a
@a
    @\n
@\uA
    typeof @\s
kap:char

Simple mathematical functions

Here’s a list of the basic mathematical functions:

  • + — Addition / complex conjugate

  • - — Subtraction / negation

  • × — Multiplication / sign (type: `, -)

  • ÷ — Division / inverse (type: `, =)

  • * — Power / e to the power of

  •  — Log base N / log base e (type: `, 8)

  •  — Root / Square root (type: `, R)

Note how each symbol has two operations. The first (i.e. “Addition”) describes the operation when the function is called with two arguments, one of the left and one on the right. This is referred to as dyadic calls. The second case (i.e. “complex conjugate” is when a function is called with one argument, passed on the right of the function name. This is referred to as to monadic calls.

Some examples of dyadic calls:

    1 + 2
3
    10 - 7
3
    4 × 8
32
    100 ÷ 2
50
    20 ÷ 9
20/9
    20 ÷ 9.0
2.2222222222222223

The last two examples show the difference in behaviour between rational and floating point arithmetic. It also shows that if only one of the arguments are floating-point, the other gets converted to floating-point before the calculation is performed.

And here are the same functions, used monadically:

    + 2j4
2.0J-4.0
    - 2
-2
    × 12
1
    ÷ 3
1/3

Often, the behaviour of monadic and dyadic calls to the same function is related (for example, the monadic version of - is simply the same as the dyadic version, but with 0 as a left argument). However, other times the two behaviours are just tangentially related, and at other times they are completely independent.

Order of evaluation

With a few exceptions, the right argument of a function call will always interpret everything to the right as a single expression. Another way to phrase it is the evaluation is right-to-left:

    2 × 3 + 4
14
    2 × (3 + 4)
14
    (2 × 3) + 4
10

The way to think about it is that a function acts on everything to the right of the function name, unless parentheses say otherwise.

Statement separators

It is possible to specify multiple statements on a single line. Each statement is separated by (type: `, `). The statement separator overrides the order of evaluation:

    io:println 1+2 ⋄ 3+4
3
7

The result of a multi-statement expression is the result of the last expression. This is why io:println was used to print the result of the first expression.

Comments

The comment character is (type: `, ,). A comment extends to the end of the line.

    1 + 2 + 3  ⍝ This is a comment
6

Variables

Variables work similar to most other languages. They are assigned using the symbol (type: `, [):

    foo ← 1234
1234
    foo + 1
1235

Variables have lexical scope, and are assigned to the innermost scope where they were first referenced.

Arrays

Array dimensionality

All arrays have a dimensionality, or “rank” as it is often referred to. Arrays in most languages are 1-dimensional, meaning that values in the array are addressed using a single number. When creating an array using the syntax described in the previous section, the result is a 1-dimensional array.

Rank-0 arrays

A rank-0 array contains a single value:

zero dim

All scalar values such as numbers or characters can be seen as rank-0 arrays.

Rank-1 arrays

Rank-1 arrays are often referred to as vectors, and are the default type of arrays in almost all programming languages. Elements are referenced using a single index:

one dim

Rank-2 arrays

A 2-dimensional array is similar to a spreadsheet, and have elements that are indexed using two numbers:

two dim

Rank-3 arrays

One can think of 3-dimensional arrays as a stack of 2-dimensional arrays, where the first index indicates the sheet, the second the row and the third is the column:

three dim

Rank-4 arrays

A 4-dimensional array can be thought of as multiple stacks of sheets. One needs 4 numbers to find a given cell, with the first number being the stack and the remaining three numbers as per the rank-3 array.

four dim

Kap supports arrays with a large number of dimensions (the exact number is 231-1), but in practice it’s rare to work with arrays with more than 4 dimensions. The principles that are illustrated in the previous paragraphs extend naturally to any number of dimensions.

Simple 1-dimensional arrays

Not counting the 0-dimensional array which is just a scalar value, the simplest form of an array is the 1-dimensional array. They are written by separating values by space. Note how arrays are displayed by drawing a box around them:

    1 2 3 4
┌→──────┐
│1 2 3 4│
└───────┘

There are many ways to access individual elements of an array. The square bracket syntax is probably the most familiar to users of other languages:

    foo ← 10 20 30 40
┌→──────────┐
│10 20 30 40│
└───────────┘
    foo[1]
20

The value inside the square brackets can also be an array, with the result being a new array which is the selection based on that array:

      foo[0 2]
┌→────┐
│10 30│
└─────┘

There is nothing stopping you from repeating indexes:

    (10 20 30 40)[0 1 0 2 3 1 0]
┌→───────────────────┐
│10 20 10 30 40 20 10│
└────────────────────┘

Multi-dimensional arrays

As mentioned in the summary above, in most programming languages, arrays can only have a single dimensions. I.e. elements are dereferenced using a single index. Kap arrays can have any number of dimensions. To help creating arrays with more dimensions, the function (type: `, r) is used. This function is referred to as “reshape”, and takes the desired dimensionality on the left, and a value to be reshaped on the right:

    2 3 ⍴ 1 2 3 4 5 6
┌→────┐
↓1 2 3│
│4 5 6│
└─────┘

The result is an array with 2 rows and 3 columns. If the size of the right argument is too small, it will simply loop around and start taking values from the beginning of the input. If the array is too large, any extra elements will simply be dropped:

    2 5 ⍴ 1 2 3 4
┌→────────┐
↓1 2 3 4 1│
│2 3 4 1 2│
└─────────┘
    2 3 ⍴ 1 2 3 4 5 6 7 8 9 10
┌→────┐
↓1 2 3│
│4 5 6│
└─────┘

This behaviour can be leveraged in various ways, for example by creating a checkerboard pattern (assuming the number of columns is odd):

    5 5 ⍴ 1 0
┌→────────┐
↓1 0 1 0 1│
│0 1 0 1 0│
│1 0 1 0 1│
│0 1 0 1 0│
│1 0 1 0 1│
└─────────┘

If is called monadically (i.e. with just a single argument to the right), it will return an array of numbers representing the dimensionality of the argument:

    a ← 3 15 ⍴ 1 2 3
┌→────────────────────────────┐
↓1 2 3 1 2 3 1 2 3 1 2 3 1 2 3│
│1 2 3 1 2 3 1 2 3 1 2 3 1 2 3│
│1 2 3 1 2 3 1 2 3 1 2 3 1 2 3│
└─────────────────────────────┘
    ⍴ a
┌→───┐
│3 15│
└────┘

Getting values from a multi-dimensional array using square brackets can be done by separating the dimensions using ;:

    a ← 3 2 ⍴ 100 200 300 400 500 600
┌→──────┐
↓100 200│
│300 400│
│500 600│
└───────┘
    a[0;1]
200

The indexes at a given axis does not have to be a scalar number, it can also be an array, in which case all the given indexes are used. The following gets the second, then then first row of the second column:

    a[1 0 ; 1]
┌→──────┐
│400 200│
└───────┘

If an axis is left blank, all elements along that axis are picked. The following gets all elements on the last row:

    a[2;]
┌→──────┐
│500 600│
└───────┘

Creating sequences of numbers

In the later examples, we’ll be using the (type: `, i) a lot. This function is called iota, or sometimes index generator. It is used to generate an array of indexes into an array of a given size. For 1-dimensional arrays, this is simply N numbers starting at 0:

    ⍳20
┌→────────────────────────────────────────────────┐
│0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19│
└─────────────────────────────────────────────────┘
    10 10 ⍴ ⍳100
┌→────────────────────────────┐
↓ 0  1  2  3  4  5  6  7  8  9│
│10 11 12 13 14 15 16 17 18 19│
│20 21 22 23 24 25 26 27 28 29│
│30 31 32 33 34 35 36 37 38 39│
│40 41 42 43 44 45 46 47 48 49│
│50 51 52 53 54 55 56 57 58 59│
│60 61 62 63 64 65 66 67 68 69│
│70 71 72 73 74 75 76 77 78 79│
│80 81 82 83 84 85 86 87 88 89│
│90 91 92 93 94 95 96 97 98 99│
└─────────────────────────────┘

Scalar arrays

All values in Kap are arrays. However, some of them does not have any dimensions. I.e. they are scalar values. When calling on a scalar, it returns an empty array, which is represented by :

    ⍴ 3
⍬

Character arrays (i.e. strings)

Note how we never mentioned strings in the explanation of value types above. This is because a string in Kap is simply a 1-dimensional array where all values are characters. Strings can be entered by enclosing them in double-quotes, or they can be created using any other method that creates arrays:

    "Foo"
"Foo"
    @F @o @o
"Foo"
    10 ⍴ @a
"aaaaaaaaaa"
    ⍴ "This is a test string"
┌→─┐
│21│
└──┘

Nested arrays

Since an array can contain elements of any type, it’s possible for an array to contain other arrays. Here is a simple example:

    a ← (1 2 3) (4 5) 6 7 8
┌→──────────────────┐
│┌→────┐ ┌→──┐ 6 7 8│
││1 2 3│ │4 5│      │
│└─────┘ └───┘      │
└───────────────────┘
    ⍴ a
┌→┐
│5│
└─┘
    a[0 3 4]
┌→──────────┐
│┌→────┐ 7 8│
││1 2 3│    │
│└─────┘    │
└───────────┘

Note: At this point it is important to note a possibly unexpected behaviour when looking up individual elements using bracket notation:

    a[0]
┌───────┐
│┌→────┐│
││1 2 3││
│└─────┘│
└───────┘

The extra box around the result is because the value is “enclosed” to ensure that the result is scalar. This is explained in the chapter Enclosing data. For now, we can ignore this and instead use “period notation” which can be used when looking up a single value in a container object:

    a.(0)
┌→────┐
│1 2 3│
└─────┘

Period notation is also useful when dereferencing values in a deeply nested object:

    a.(0).(2)
3

Concatenating arrays

Two arrays can be concatenated using the , function:

    1 2 3 4 , 5 6 7
┌→────────────┐
│1 2 3 4 5 6 7│
└─────────────┘

When applied on multi-dimensional arrays, , concatenates elements along the last axis:

    a ← 3 4 ⍴ ⍳ 12
┌→────────┐
↓0 1  2  3│
│4 5  6  7│
│8 9 10 11│
└─────────┘
    b ← 3 5 ⍴ 100+⍳15
┌→──────────────────┐
↓100 101 102 103 104│
│105 106 107 108 109│
│110 111 112 113 114│
└───────────────────┘
    a , b
┌→────────────────────────────┐
↓0 1  2  3 100 101 102 103 104│
│4 5  6  7 105 106 107 108 109│
│8 9 10 11 110 111 112 113 114│
└─────────────────────────────┘

It is also possible to use to concatenate along the first axis:

    a ← 3 4 ⍴ ⍳ 12
┌→────────┐
↓0 1  2  3│
│4 5  6  7│
│8 9 10 11│
└─────────┘
    b ← 6 4 ⍴ 100+⍳24
┌→──────────────┐
↓100 101 102 103│
│104 105 106 107│
│108 109 110 111│
│112 113 114 115│
│116 117 118 119│
│120 121 122 123│
└───────────────┘
    a ⍪ b
┌→──────────────┐
↓  0   1   2   3│
│  4   5   6   7│
│  8   9  10  11│
│100 101 102 103│
│104 105 106 107│
│108 109 110 111│
│112 113 114 115│
│116 117 118 119│
│120 121 122 123│
└───────────────┘

Scalar extension applies as per normal when concatenating a scalar with an array:

    a ← 2 2 ⍴ 10 20 30 40
┌→────┐
↓10 20│
│30 40│
└─────┘
    1 , a
┌→──────┐
↓1 10 20│
│1 30 40│
└───────┘

Turning an array into a 1-dimensional array

Calling the function , monadically will create a 1-dimensional array with the same number of elements as the original array:

    a ← 2 3 ⍴ ⍳6
┌→────┐
↓0 1 2│
│3 4 5│
└─────┘
    ,a
┌→──────────┐
│0 1 2 3 4 5│
└───────────┘

Making a 1-dimensional array into a table

The function can be called monadically in which case it’s referred to as “table”. It converts a one-dimensional array into a 2-dimensional array with a single column:

    ⍪ 1 2 3
┌→┐
↓1│
│2│
│3│
└─┘
    ⍴ ⍪ 1 2 3
┌→──┐
│3 1│
└───┘

Scalar functions

Many functions in Kap are scalar functions. These functions include all mathematical functions mentioned above, as well as many others. A list of all scalar functions in Kap can be found in the reference documentation.

A scalar function works on scalar values, such as individual numbers. They can also be used with arrays, and if so, the function is applied element-wise on the values in the array:

    1 2 3 + 10 20 30
┌→───────┐
│11 22 33│
└────────┘

If either of the arguments is a scalar, then that scalar is applied to all elements in the other argument. This is referred to as scalar extension.

    1 + 10 20 30
┌→───────┐
│11 21 31│
└────────┘

It is an error if the two arguments to a scalar function have different dimensions:

    1 2 3 + 10 20 30 40
Error at: 1:7: +: Arguments must be of the same dimension, or one of the arguments must be a scalar. aDimensions=[3], bDimensions=[4]

Operators

Operators act on functions, and yield another function. Kap contains a large number of built-in operators. One of the more useful ones is /, called reduce. This works similar to reduction in most functional languages.

Reduce

The operator comes after the function on which it acts:

    +/ 1 2 3 4 5 6
21

When applied to a multi-dimensional array, / acts on the last axis:

    a ← 4 8 ⍴ 100+⍳32
┌→──────────────────────────────┐
↓100 101 102 103 104 105 106 107│
│108 109 110 111 112 113 114 115│
│116 117 118 119 120 121 122 123│
│124 125 126 127 128 129 130 131│
└───────────────────────────────┘
    +/a
┌→───────────────┐
│828 892 956 1020│
└────────────────┘

Using (type: `, /), acts on the first axis:

    +⌿a
┌→──────────────────────────────┐
│448 452 456 460 464 468 472 476│
└───────────────────────────────┘

It is also possible to specify an axis parameter to choose precisely which axis to reduce over:

    +/[2] 2 3 4 5 ⍴ ⍳120
┌┌→──────────────────┐
│↓ 30  34  38  42  46│
││110 114 118 122 126│
││190 194 198 202 206│
│├→──────────────────┤
│↓270 274 278 282 286│
││350 354 358 362 366│
││430 434 438 442 446│
└└───────────────────┘

Outer product

The outer product operator, (type: `, K) creates a permutation matrix with the result of the function applied to all combinations of the input arguments. For example, it can be used to create a multiplication table:

    a ← 1+⍳5
┌→────────┐
│1 2 3 4 5│
└─────────┘
    a ×⌻ a
┌→────────────┐
↓1  2  3  4  5│
│2  4  6  8 10│
│3  6  9 12 15│
│4  8 12 16 20│
│5 10 15 20 25│
└─────────────┘

Each

The operator ¨ (type: `, 1) is called “each”, and applies the function on each element in the input array. This is very similar to the “map” function in most functional languages:

    io:println¨ 10 20 30
10
20
30
┌→───────┐
│10 20 30│
└────────┘

Duplicate

Another useful operator is commute/duplicate, (type: `, T) which has two uses. When the derived function is called dyadically, it calls the original function with the two arguments swapped:

    4 -⍨ 1
-3

When called monadically, it calls the functional dyadically with the same argument on the left and right:

    ×⍨ 10
100

Using this operator, the multiplication table above can be written very concisely. It’s left as a small exercise for the reader.

Functions

Inline functions (lambda expressions)

Inline functions are defined using { and }. The entire expression acts as any other function and when called, the variables (type: `, w) and (type: `, w) contains the values of the left and right arguments.

    10 {⍺ + ⍵×5} 30
160
    {1+⍺+⍵}/ 10 20 30 40 50
154

Named local functions

A local function is created using (type: `, U). The left side of the assignment is the name of the function, and the right side is a function, written as it is called in code. The following creates an alias for the function - called minus:

    minus ⇐ -
    4 minus 1
3

This method is also the way to give a name to a lambda expression:

    leftPlus5Times ⇐ {⍺ + ⍵×5}
    10 leftPlus5Times 100
510

Global functions

Global functions are declared using . We’re not going to need those for now, but for anyone interested, more information can be found about it in the reference documentation.

More useful scalar functions

Aside from the mathematical functions mentioned above, there are plenty of others:

Random numbers

The function ? returns a random number between 0 and n-1. To create an array of random numbers from 1 to 10:

    1 + ?20⍴10
┌→────────────────────────────────────────┐
│8 7 3 4 3 10 2 10 9 3 2 6 6 3 3 7 8 7 1 3│
└─────────────────────────────────────────┘

When called dyadically as, a ? b returns a unique random numbers between 0 and b-1. Obviously a must be less than or equal to b.

    15?30
┌→────────────────────────────────────────┐
│13 18 22 29 17 0 8 24 1 10 26 19 20 28 16│
└─────────────────────────────────────────┘

Min/max

The functions (type: `, d) and (type: `, s) find the minimum and maximum of two values:

    3 ⌊ 1 2 3 4 5 6
┌→──────────┐
│1 2 3 3 3 3│
└───────────┘
    3 ⌈ 1 2 3 4 5 6
┌→──────────┐
│3 3 3 4 5 6│
└───────────┘

These functions are useful combined with the reduce operator to find the minimum/maximum values in an array:

    ⌈/ 3 0 9 2 4 7 7 8 7 9
9

To find the maximum value in each row:

    a ← 4 10 ⍴ ?40⍴1000
┌→──────────────────────────────────────┐
↓147 509 740 337 770  33 801 667 540 542│
│947 837 386 864 921 430 160 411 624 810│
│110 377 311  90  58 396  82 469 845 470│
│ 20 141 668 623 491 790 839 190 711 746│
└───────────────────────────────────────┘
    ⌈/a
┌→──────────────┐
│801 947 845 839│
└───────────────┘

Rounding numbers

The same functions called monadically rounds up or down:

    ⌈ 1 1.1 2.5 2.9 5.3
┌→────────┐
│1 2 3 3 6│
└─────────┘
    ⌊ 1 1.1 2.5 2.9 5.3
┌→────────┐
│1 1 2 2 5│
└─────────┘

To round towards even, use math:round:

    math:round 1 1.5 2.2 2.5 3 3.5
┌→──────────┐
│1 2 2 2 3 4│
└───────────┘

Boolean functions

Booleans in Kap are represented by the integers 0 and 1.

Comparison functions are scalar functions that compare values and return a boolean value depending on how the left value relates to the right:

    10 < 5 10 25 30
┌→──────┐
│0 0 1 1│
└───────┘
    10 ≤ 5 10 25 30
┌→──────┐
│0 1 1 1│
└───────┘

The following comparison functions exist:

  • < — Less than

  • > — Greater than

  •  — Less than or equal to (type: `, 3)

  •  — Greater than or equal to (type: `, 4)

  • = — Equal to

  •  — Not equal to (type: `, 8)

Additionally, the following boolean functions exist, which relates one boolean to another:

  •  — Logical and (type: `, 0)

  •  — Logical not (type: `, 9)

  •  — Logical nand (type: `, ))

  •  — Logical nor (type: `, ()

  • ~ — Logical not

There are no functions for logical xor and xnor, because these functions would be equivalent to and =.

    0 1 ∧⌻ 0 1  ⍝ Display truth matrix for the logical 'and' function
┌→──┐
↓0 0│
│0 1│
└───┘

Practical example of logical functions

Problem: Given a list of numbers, we want to multiply all values above 5 by 10, and leave the remaining numbers as they are.

For the purposes of the below examples, the values are available in the variable nums:

    nums ← 1 2 10 11 3 4 5 10
┌→─────────────────┐
│1 2 10 11 3 4 5 10│
└──────────────────┘

Straightforward imperative solution

A functional programmer may approach this as a mapping problem. You map each value over a function which multiplies the result, or not. This can easily be implemented in Kap like so:

    ⍝ This function performs the computation on one value
    maybeMultiply ⇐ { if (⍵ > 5) {⍵×10} else {⍵} }

    ⍝ Map the values over the newly defined function
    maybeMultiply¨ nums
┌→────────────────────┐
│1 2 100 110 3 4 5 100│
└─────────────────────┘

Array-oriented soltuion

The above solution works, but it’s not the ideal approach. A better way to think about the problem is that we want to create a new array, containing the value 1 where a number should not be multiplied, and 10 where it shoud. Then we can simply multiply this new array with nums and we’re done.

Here is one way to do this:

    nums × (1 10)[nums > 5]
┌→────────────────────┐
│1 2 100 110 3 4 5 100│
└─────────────────────┘

Array-oriented mathematical approach

The problem is how to turn the values 0 1 into 1 10. In the previous example we did this by using the result of the comparison function as an index into a 2-element array. Another way to do it is to multiply the value by 9 and add 1. This turns 0 into 1 and 1 into 10:

    nums × 1+9×nums>5
┌→────────────────────┐
│1 2 100 110 3 4 5 100│
└─────────────────────┘

Filter arrays

The function / is used to filter arrays. Note that / is both an operator and a function, and while this symbol’s role as the reduction operator was discussed above, when called as a function it is used (among other things) to filter arrays.

In its simplest form, the function takes a bit-array on the left, and an array of the same size on the right, and keeps the values where the left argument contains a 1:

    1 1 0 1 / 1 2 3 4
┌→────┐
│1 2 4│
└─────┘

The filter functionality is just a special case of the more general case where the argument on the left indicates the number of times a value should be replicated. Hence, the name 'replicate' is often used for this function:

    1 3 0 2 2 / 1 2 3 4 5
┌→──────────────┐
│1 2 2 2 4 4 5 5│
└───────────────┘

When applied to arrays of higher dimensions, the selection is performed along the last axis:

    1 0 2 3 / 3 4 ⍴ ⍳12
┌→───────────────┐
↓0  2  2  3  3  3│
│4  6  6  7  7  7│
│8 10 10 11 11 11│
└────────────────┘

The alternative symbol (type: `, /}) can be used to perform the selection along the first axis:

    1 0 4 ⌿ 3 4 ⍴ ⍳12
┌→────────┐
↓0 1  2  3│
│8 9 10 11│
│8 9 10 11│
│8 9 10 11│
│8 9 10 11│
└─────────┘

It is also possible to use axis arguments (an axis indicator specified inside square brackets after the name of the function) to specify which axis to perform the selection on. The following example performs a selection on the middle axis of a 3-dimensional array:

    1 0 4 /[1] 2 3 4 ⍴ ⍳24
┌┌→──────────┐
│↓ 0  1  2  3│
││ 8  9 10 11│
││ 8  9 10 11│
││ 8  9 10 11│
││ 8  9 10 11│
│├→──────────┤
│↓12 13 14 15│
││20 21 22 23│
││20 21 22 23│
││20 21 22 23│
││20 21 22 23│
└└───────────┘

Practical example of filters

Problem: You have an array of names of people in names, and an array of their ages in ages. Get a list of the names whose age is greater or equal to 20:

    names ← "Arjun" "Rishi" "Ming Hao" "Harish" "Jon" "Carl"
    ages ← 10 25 54 34 4 76
    (ages ≥ 20) / names
┌→─────────────────────────────────┐
│"Rishi" "Ming Hao" "Harish" "Carl"│
└──────────────────────────────────┘

Sorting

Sorting is done using monadic and . The former sorts ascending and the latter descending. To sort the result from the previous example:

    ∧ "Rishi" "Ming Hao" "Harish" "Carl"
┌→─────────────────────────────────┐
│"Carl" "Harish" "Ming Hao" "Rishi"│
└──────────────────────────────────┘

For more complex sorting, the grade functions can be used. Grade down (type: `, $) returns a list of indexes into the array in ascending order. Grade up (type: `, #) does the same, but sorts descending.

Given the names in the previous example, we can sort their names based on their ages:

    names[⍋ages]
┌→───────────────────────────────────────────────┐
│"Jon" "Arjun" "Rishi" "Harish" "Ming Hao" "Carl"│
└────────────────────────────────────────────────┘

Reshaping data

Kap provides a wide range of functions to manipulate the valius in an array to put it in the shape most appropriate for solving a given problem.

Transposing arrays

The transpose function (type: `, ^) is used to reverse the axes of an array. For 2-dimensional arrays, this means that the rows becomes the columns and vice versa:

    a ← 3 4 ⍴ ⍳12
┌→────────┐
↓0 1  2  3│
│4 5  6  7│
│8 9 10 11│
└─────────┘
    ⍉ a
┌→─────┐
↓0 4  8│
│1 5  9│
│2 6 10│
│3 7 11│
└──────┘

The function can also be called dyadically, in which case it allows the user to specify precisely which axis is moved where. More information about this can be found in the reference.

Note that in Kap, along with the majority of functions that change the shape of the content, transposition does not result in a new array being allocated. Instead, it simply changes the way that the positions of values in the array is calculated.

Reflecting and rotating arrays

The functions (type: `, 7) and (type: `, 5) are used to reflect and rotate arrays.

Reflecting

When called monadically, they reflect an array along the first and last axes respectively.

For 1-dimensional arrays, this is just a reverse:

    ⌽ ⍳20
┌→────────────────────────────────────────────────┐
│19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0│
└─────────────────────────────────────────────────┘

With multi-dimensional arrays:

    a ← 3 4 ⍴ ⍳12
┌→────────┐
↓0 1  2  3│
│4 5  6  7│
│8 9 10 11│
└─────────┘
    ⊖ a
┌→────────┐
↓8 9 10 11│
│4 5  6  7│
│0 1  2  3│
└─────────┘
    ⌽ a
┌→────────┐
↓ 3  2 1 0│
│ 7  6 5 4│
│11 10 9 8│
└─────────┘

Rotating

When called dyadically, the same functions rotate an array the given number of steps to the left:

    a ← 5 20 ⍴ ⍳100
┌→──────────────────────────────────────────────────────────┐
↓ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19│
│20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39│
│40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59│
│60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79│
│80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99│
└───────────────────────────────────────────────────────────┘
    2 ⌽ a
┌→──────────────────────────────────────────────────────────┐
↓ 2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19  0  1│
│22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 20 21│
│42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 40 41│
│62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 60 61│
│82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 80 81│
└───────────────────────────────────────────────────────────┘
    ¯1 ⌽ a
┌→──────────────────────────────────────────────────────────┐
↓19  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18│
│39 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38│
│59 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58│
│79 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78│
│99 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98│
└───────────────────────────────────────────────────────────┘

The left argument can also be an array, indicating the amount by which each row/column should be rotated:

    1 2 ¯5 0 1 ⌽ a
┌→──────────────────────────────────────────────────────────┐
↓ 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19  0│
│22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 20 21│
│55 56 57 58 59 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54│
│60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79│
│81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 80│
└───────────────────────────────────────────────────────────┘

Enclosing data

The enclose function (type: `, z) is used to create nested arrays from non-nested data. In its simplest form, it creates a scalar (zero-dimensional) value from an array:

    a ← ⊂ 1 2 3 4
┌─────────┐
│┌→──────┐│
││1 2 3 4││
│└───────┘│
└─────────┘
    ⍴ a
⍬

Since scalar functions (such as +) acts on scalar values by replicating them to each value in the other argument, one can do the following:

    (⊂1 2 3) + (10 20 30)
┌→───────────────────────────────┐
│┌→───────┐ ┌→───────┐ ┌→───────┐│
││11 12 13│ │21 22 23│ │31 32 33││
│└────────┘ └────────┘ └────────┘│
└────────────────────────────────┘

The content of an enclosed value can be recovered using the disclose function (type: `, x):

    ⊃ a
┌→──────┐
│1 2 3 4│
└───────┘

Converting a nested array into a multi-dimensional array

Given a nested array, the disclose function can be used to turn each element in an array into a new axis in a new array which will have one more dimension than the original. Example:

    a ← (⊂100×1+⍳4) + 1+⍳4
┌→──────────────────────────────────────────────────────────────────────┐
│┌→──────────────┐ ┌→──────────────┐ ┌→──────────────┐ ┌→──────────────┐│
││101 201 301 401│ │102 202 302 402│ │103 203 303 403│ │104 204 304 404││
│└───────────────┘ └───────────────┘ └───────────────┘ └───────────────┘│
└───────────────────────────────────────────────────────────────────────┘
    ⊃ a
┌→──────────────┐
↓101 201 301 401│
│102 202 302 402│
│103 203 303 403│
│104 204 304 404│
└───────────────┘

Converting a multi-dimensional array into a nested array

To perform the opposite of the disclose function above, one uses enclose, but with an axis argument:

    a ← ⊃ (⊂100×1+⍳4) + 1+⍳4
┌→──────────────┐
↓101 201 301 401│
│102 202 302 402│
│103 203 303 403│
│104 204 304 404│
└───────────────┘
    ⊂[0] a
┌→──────────────────────────────────────────────────────────────────────┐
│┌→──────────────┐ ┌→──────────────┐ ┌→──────────────┐ ┌→──────────────┐│
││101 102 103 104│ │201 202 203 204│ │301 302 303 304│ │401 402 403 404││
│└───────────────┘ └───────────────┘ └───────────────┘ └───────────────┘│
└───────────────────────────────────────────────────────────────────────┘

Of course, another axis can also be used:

    ⊂[1] a
┌→──────────────────────────────────────────────────────────────────────┐
│┌→──────────────┐ ┌→──────────────┐ ┌→──────────────┐ ┌→──────────────┐│
││101 201 301 401│ │102 202 302 402│ │103 203 303 403│ │104 204 304 404││
│└───────────────┘ └───────────────┘ └───────────────┘ └───────────────┘│
└───────────────────────────────────────────────────────────────────────┘

Destructuring assignment

Very often when working with actual data, it comes in a tabular form (usually a CSV file or a spreadsheet). Kap is most powerful when the individual columns are separated out, such as in a variable.

One can use the functions described above to extract the values one wants into a list, and then use destructuring assignment to assign the values to a set of variables.

Given an array of some values, the values in that array can be assigned to a set of variables like so:

    (a b c d) ← 1 "Test" (⍳7) (100 200 300 400)
┌→─────────────────────────────────────────┐
│1 "Test" ┌→────────────┐ ┌→──────────────┐│
│         │0 1 2 3 4 5 6│ │100 200 300 400││
│         └─────────────┘ └───────────────┘│
└──────────────────────────────────────────┘
    c
┌→────────────┐
│0 1 2 3 4 5 6│
└─────────────┘

This is useful when extracting columns from a table (which may have been loaded using SQL, a CSV file, or loaded from a spreadsheet):

    a ← 10 2 ⍴ ⍳20
┌→────┐
↓ 0  1│
│ 2  3│
│ 4  5│
│ 6  7│
│ 8  9│
│10 11│
│12 13│
│14 15│
│16 17│
│18 19│
└─────┘
    (x y) ← ⊂[0] a
┌→────────────────────────────────────────────────────┐
│┌→───────────────────────┐ ┌→───────────────────────┐│
││0 2 4 6 8 10 12 14 16 18│ │1 3 5 7 9 11 13 15 17 19││
│└────────────────────────┘ └────────────────────────┘│
└─────────────────────────────────────────────────────┘
    x
┌→───────────────────────┐
│0 2 4 6 8 10 12 14 16 18│
└────────────────────────┘
    y
┌→───────────────────────┐
│1 3 5 7 9 11 13 15 17 19│
└────────────────────────┘

Practical example: Displaying weather data

Open-Meteo is a service that provides a REST-based API to access weather information. We will use this API to collect weather forecast data and display it in a graph.

The Open-Meteo documentation contains a lot of information about how to use it, but for our purposes, as well need is the following URL:

https://api.open-meteo.com/v1/forecast?latitude=XXXX&longitude=YYYY&hourly=temperature_2m&current=temperature_2m

Where XXXX and YYYY is the latitude and longitude of the location where we want the weather forecast. The response is a JSON document, so we can use the built-in function http:getJSON to retrieve this data and decode the JSON content for us.

To get the forecast for London:

http:getJSON "https://api.open-meteo.com/v1/forecast?latitude=51.509865&longitude=-0.118092&hourly=temperature_2m&current=temperature_2m"

Here is a function that accepts a lat/lon pair and returns the temperature forecast for that location:

temp ⇐ { res ← http:getJSON "https://api.open-meteo.com/v1/forecast?latitude=$s&longitude=$s&hourly=temperature_2m&current=temperature_2m" ⍕ ⍵ ⋄ labels/ res.("hourly")["time" "temperature_2m"] }

We can now call it like so, to get the forecast for Stockholm (the call to labels in the function attaches labels to the data for readability. It’s metadata attached to the value itself, which is why we’ll see that it disappears later when we concatenate multiple arrays, since the labels would otherwise conflict):

    temp 59.334591 18.063240
┌────────────────┬────────────────┬────────────────┬────────────────┬─────────── ... ─────────┐
│2025-12-15T00:00│2025-12-15T01:00│2025-12-15T02:00│2025-12-15T03:00│2025-12-15T     -21T23:00│
├→───────────────┴────────────────┴────────────────┴────────────────┴─────────── ... ─────────┤
│             9.3              9.4              9.3              9.2                       3.2│
└─────────────────────────────────────────────────────────────────────────────── ... ─────────┘

Let’s get the forecasts for London and Singapore as well, and collect them:

    (sg london sth) ← (1.290270 103.851959) (51.509865 ¯0.118092) (59.334591 18.063240)
┌→──────────────────────────────────────────────────────────────┐
│┌→─────────────────┐ ┌→──────────────────┐ ┌→─────────────────┐│
││1.29027 103.851959│ │51.509865 -0.118092│ │59.334591 18.06324││
│└──────────────────┘ └───────────────────┘ └──────────────────┘│
└───────────────────────────────────────────────────────────────┘
    result ← ⍪/ <¨ temp¨ sg london sth
┌→────────────────────────────────────────────────────────────────────────────── ... ─────────┐
↓24.9 25.2 25.2 25.5 26.1 26.5 26.2 25.7 25.9 25.8 25.4 25.1 24.8 24.6 24.5 24.4     25.0 25.0│
│10.8 10.5 10.4 10.6 10.4 10.5 10.5 10.3 10.4 10.5 10.8 11.1 11.3 11.2 11.3 11.2 ...  5.0  5.0│
│ 9.3  9.4  9.3  9.2  9.0  9.1  9.1  8.9  8.7  8.5  8.4  8.2  8.1  8.1  8.2  8.3      3.4  3.2│
└─────────────────────────────────────────────────────────────────────────────── ... ─────────┘

The call to is needed to ensure that the arrays containing the values are 2-dimensional, so that the concatenation will do the right thing. For more information, see the reference.

Finally, we can render it in a chart:

    chart:line result

This will render something like this:

turbo tutorial temp

Extracting information from arrays

We’ve already seen bracket indexing to extract specific values from arrays. This is useful, but a more common way to extract data is by taking or dropping values from an array (for example, getting the first 10 rows, or removing the 3 last columns).

There are two functions associated with this, appropriately named “take” (type: `, y) and “drop” (type: `, u).

Take

When called dyadically, takes a given number of elements from an array, and removes the rest. If the number is negative, it takes elements from the end of the axis.

Take the first 3 elements:

    3 ↑ 1 2 3 4 5 6 7
┌→────┐
│1 2 3│
└─────┘

Take the last 4 elements:

    ¯4 ↑ 1 2 3 4 5 6 7
┌→──────┐
│4 5 6 7│
└───────┘

From the first row, take the two first columns:

    a ← 3 3 ⍴ ⍳9
┌→────┐
↓0 1 2│
│3 4 5│
│6 7 8│
└─────┘
    1 2 ↑ a
┌→──┐
↓0 1│
└───┘

Instead of a count, null can be used to specify that you want all the elements alogn an axis. Take the first 2 columns of all the rows:

    a ← 5 5 ⍴ ⍳25
┌→─────────────┐
↓ 0  1  2  3  4│
│ 5  6  7  8  9│
│10 11 12 13 14│
│15 16 17 18 19│
│20 21 22 23 24│
└──────────────┘
    null 2 ↑ a
┌→────┐
↓ 0  1│
│ 5  6│
│10 11│
│15 16│
│20 21│
└─────┘

When taking more than the available number of elements, by default 0 is used to fill in the missing values:

    5 6 ↑ 3 3 ⍴ ⍳9
┌→──────────┐
↓0 1 2 0 0 0│
│3 4 5 0 0 0│
│6 7 8 0 0 0│
│0 0 0 0 0 0│
│0 0 0 0 0 0│
└───────────┘

Drop

Drop works similar to take, except that the numbers specify the number of cells to remove, as opposed to the number of cells to keep.

    3 ↓ ⍳15
┌→───────────────────────────┐
│3 4 5 6 7 8 9 10 11 12 13 14│
└────────────────────────────┘

Drop the first row and the last 4 columns:

    a ← 5 5 ⍴ ⍳25
┌→─────────────┐
↓ 0  1  2  3  4│
│ 5  6  7  8  9│
│10 11 12 13 14│
│15 16 17 18 19│
│20 21 22 23 24│
└──────────────┘
    1 ¯4 ↓ a
┌→─┐
↓ 5│
│10│
│15│
│20│
└──┘

Pick

The function (type: `, X) is called “pick” and it used to select elements from an array by specifying its coordinates.

A simple case with a 1-dimensional array:

    2 4 5 ⊇ 100+⍳10
┌→──────────┐
│102 104 105│
└───────────┘

If the array is multi-dimensional, each element is selected using an array of values the same length as the dimensionality of the array. For example, if the array is 3-dimensional, a cell specification consists of a 3-element array:

    a ← 3 4 5 ⍴ ⍳69
┌┌→─────────────┐
│↓ 0  1  2  3  4│
││ 5  6  7  8  9│
││10 11 12 13 14│
││15 16 17 18 19│
│├→─────────────┤
│↓20 21 22 23 24│
││25 26 27 28 29│
││30 31 32 33 34│
││35 36 37 38 39│
│├→─────────────┤
│↓40 41 42 43 44│
││45 46 47 48 49│
││50 51 52 53 54│
││55 56 57 58 59│
└└──────────────┘
    (1 2 1) (0 0 0) (2 3 3) ⊇ a
┌→──────┐
│31 0 58│
└───────┘

Note: if the array is multi-dimensional and one only wants to retrieve a single value, this value must be enclosed. In the example below, if the numbers (1 2) had not been enclosed, would think that 2 elements from a 1-dimensional array was requested. This would not match the actual array, so an error will be raised.

    (⊂1 2) ⊇ 3 3 ⍴ ⍳9
5

Without the enclose:

    1 2 ⊇ 3 3 ⍴ ⍳9
Error at: 1:5: ⊇: Lookup index has rank 0. Not compatible with rank: 2

Practical example: Computing average of die rolls

Problem: You have the results of a set of die rolls, and you want to process the results.

In order to not have to actually roll the dies, we’ll just simulate them and confirm that the random number generator has the correct distribution by plotting the expected distribution. So, let’s phrase the problem as such: Given n rolls of m d-sided dice, compute the sums of the rolls and display the results.

For the purpose of this experiment, let’s set m to 10 initially (to make it easy to see the numbers), n to 6, and d to 6.

(m n d) ← 10 6 6

Create an m-by-n array of numbers, generate random numbers from them and add 1 to account for the fact that the dice goes from 1 to n:

    rolls ← 1 + ?m n ⍴ d
┌→──────────┐
↓4 6 2 3 4 3│
│3 1 4 5 4 1│
│3 2 3 6 5 2│
│2 3 5 4 3 4│
│2 5 6 2 4 6│
│6 4 6 4 6 1│
│5 5 4 3 2 3│
│5 3 1 1 6 4│
│5 1 5 3 2 2│
│6 1 6 5 2 5│
└───────────┘

Sum the results of all the rolls. This is just a sum reduction by rows:

    +/rolls
┌→────────────────────────────┐
│22 18 21 21 25 27 22 20 18 25│
└─────────────────────────────┘

Sort the results and generate a histogram:

    ⍸˝ ∧ +/rolls
┌→──────────────────────────────────────────────────────┐
│0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 1 2 2 0 0 2 0 1│
└───────────────────────────────────────────────────────┘

The ⍸˝ is the inverse of monadic , which will be explained later. But as a function of its own, it simply creates an array of numbers where the number at each index indicates how many times that number appeared in the input. For consistency and performance reasons, this function expects the input to be sorted.

Setting m to 10 was much too low. Here’s the entire thing on a single line, with 10000 rolls:

    (m n d) ← 10000 6 6
┌→────────┐
│10000 6 6│
└─────────┘
    result ← ⍸˝ ∧ +/ 1 + ?m n ⍴ d
┌→──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│0 0 0 0 0 0 1 0 8 7 19 59 110 154 264 346 482 641 740 842 849 911 937 828 760 603 445 375 230 162 88 73 46 11 6 2 1│
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

We can now display it in tabular form:

    (⍳≢result) , ⍪result
┌→─────┐
↓ 0   0│
│ 1   0│
│ 2   0│
│ 3   0│
│ 4   0│
│ 5   0│
│ 6   1│
│ 7   0│
│ 8   8│
│ 9   7│
│10  19│
│11  59│
│12 110│
│13 154│
│14 264│
│15 346│
│16 482│
│17 641│
│18 740│
│19 842│
│20 849│
│21 911│
│22 937│
│23 828│
│24 760│
│25 603│
│26 445│
│27 375│
│28 230│
│29 162│
│30  88│
│31  73│
│32  46│
│33  11│
│34   6│
│35   2│
│36   1│
└──────┘

Or, as a chart:

    chart:bar result

Which results in the following:

dice

Getting data into Kap

Kap provides a low-level stream-based API to access various file and network resources. However, most of the time the higher level data access functions are sufficient.

Loading a text file

To load a text file into an array, where each row is a string, use io:read. Let’s assume there is a text file called abcd.txt containing the following content:

this
is
a
text
file

Then, the content can be read like so:

    io:read "abcd.txt"
┌→────────────────────────────┐
│"this" "is" "a" "text" "file"│
└─────────────────────────────┘

Loading a CSV file

For this example, assume the file report.csv contains the following content:

Name,Team,Category
"Peter","Sweden",5
"Lars","Norway",4
"Borui","China",3
"Safwan","Singapore",2

Loading the data results in the following:

    a ← io:readCsv "/home/elias/report.csv"
┌→──────────────────────────────┐
↓  "Name"      "Team" "Category"│
│ "Peter"    "Sweden"        "5"│
│  "Lars"    "Norway"        "4"│
│ "Borui"     "China"        "3"│
│"Safwan" "Singapore"        "2"│
└───────────────────────────────┘

CSV is a fairly underspecified data format, and there is no type information included in it. Also, the headers are just cells like any other.

The function labels assigns labels to an axis, which is very useful when working with the data. The following expression takes the first row and uses it as headers for the remaining rows:

    a ← { (>1↑⍵) labels 1↓a } a
┌────────┬───────────┬────────┐
│    Name│       Team│Category│
├→───────┴───────────┴────────┤
↓ "Peter"    "Sweden"      "5"│
│  "Lars"    "Norway"      "4"│
│ "Borui"     "China"      "3"│
│"Safwan" "Singapore"      "2"│
└─────────────────────────────┘

We can also convert the third column into a numeric value using the function (type: `, ;):

    { (0 ¯1 ↓ ⍵) , ⍎¨ null ¯1 ↑ ⍵ } a
┌────────┬───────────┬────────┐
│    Name│       Team│Category│
├→───────┴───────────┴────────┤
↓ "Peter"    "Sweden"        5│
│  "Lars"    "Norway"        4│
│ "Borui"     "China"        3│
│"Safwan" "Singapore"        2│
└─────────────────────────────┘

What we did above was to take the last column, convert all the cells to numbers, and then concatenate back all but the last column. This is obviously a bit cumbersome, so to avoid this, the operator (type: `, G) can be used. This operator calls the function to the right, then applies the function on the left to the result, and then reverses the action that the first function produced. In this particular case, it puts back the columns that were previously removed:

    ⍎¨⍢(null ¯1 ↑) a
┌────────┬───────────┬────────┐
│    Name│       Team│Category│
├→───────┴───────────┴────────┤
↓ "Peter"    "Sweden"        5│
│  "Lars"    "Norway"        4│
│ "Borui"     "China"        3│
│"Safwan" "Singapore"        2│
└─────────────────────────────┘

Loading spreadsheets

The JVM version of Kap provides functions to load and save data to/from spreadsheets. Currently OpenDocument and Excel formats are supported. This is done using the functions libreoffice:read/libreoffice:write and msoffice:read/msoffice:write.

The read functions are monadic and accepts a filename as its argument. The first sheet in the file is loaded and converted to a Kap array. The write functions are dyadic, and accepts a filename as the left argument and the data to write as the right argument.

These functions are not available in the native or Javascript versions of Kap. However, it is possible to load Excel data into the web version via the UI. Click on the sidebar to load the file.

Searching for data in arrays

Determine if an object exists in an array

The function (type: `, e) takes an array on the left, and for each element in that array, check if the element exists in the right argument. The result is an array of the same shape as the left argument, where each cell is a 1 or 0 depending on whether the value was found or not.

    a ← 3 2 ⍴ "foo" "bar" "abc" "def" "test" "abcdef"
┌→──────────────┐
↓ "foo"    "bar"│
│ "abc"    "def"│
│"test" "abcdef"│
└───────────────┘
    "foo" "abcdef" "qwert" "abcd" "testtest" "def" ∊ a
┌→──────────┐
│1 1 0 0 0 1│
└───────────┘

One way this function can be used is to create a selection mask. The following filters out any characters not in validChars:

    validChars ← ⎕a,⎕d
"abcdefghijklmnopqrstuvwxyz0123456789"
    s ← "abc,123  foo"
"abc,123  foo"
    (s ∊ validChars) / s
"abc123foo"

Some special variables and functions with names starting with a (type: `, l) provide useful shortcuts to commonly used features. ⎕a is a list of the lower case ASCII letters a-z, ⎕A is an array of the uppercase letters A-Z and ⎕d is the decimal digits 0-9.

If we want to do the opposite, simply negate the mask before selecting:

    s ← "abc1234test9876abc9988"
"abc1234test9876abc9988"
    (~s ∊ ⎕a) / s
"123498769988"

Find the index of an object in an array

The dyadic version of is used to determine where in an array a certain value is located.

    10 20 30 40 ⍳ 20
1
    10 20 30 40 ⍳ 33
4

In the first example, the value 20 was found at the second location in the left argument, so the index 1 is returned.

In the second example, the value is not found, so the first index after the last argument is returned.

Another way to think about the behaviour of dyadic is as way to map a list of values into an alphabet:

    hexchars ← "0"…"9a"…"f"
"0123456789abcdef"
    hexchars ⍳ "1222ca3fd2c88f5d01395508c513ecba"
┌→──────────────────────────────────────────────────────────────────────────┐
│1 2 2 2 12 10 3 15 13 2 12 8 8 15 5 13 0 1 3 9 5 5 0 8 12 5 1 3 14 12 11 10│
└───────────────────────────────────────────────────────────────────────────┘

In the example above, we’re using the (type: `, m) function, called “range” to generate the sequence of hex digits. See reference for details.

Find subsequences

The function (type: `, E) is used to find subsequences in an array. The left argument is the value to search for, and the right argument is the array to search. It returns a bitmap where the value was found:

    1 2 3 ⍷ 10 20 1 2 3 30 40 1 2 1 2 3 50 Link
┌→────────────────────────┐
│0 0 1 0 0 0 0 0 0 1 0 0 0│
└─────────────────────────┘

One can also search for subarrays of higher dimension:

    a ← 4 4 ⍴ "abcdabefcdxyefxx"
┌→───┐
↓abcd│
│abef│
│cdxy│
│efxx│
└────┘
    res ← (2 2 ⍴ "cdef") ⍷ a
┌→──────┐
↓0 0 1 0│
│0 0 0 0│
│1 0 0 0│
│0 0 0 0│
└───────┘
    ⍝ Find the number of occurrences
    +/,res
2

Overlapping results are handled correctly:

    "aba" ⍷ "ababacd" Link
┌→────────────┐
│1 0 1 0 0 0 0│
└─────────────┘

The function is also used to check if array starts with a specific sequence:

    ↑ "abc" ⍷ "abcteststring"
1

Note that thanks to the use of lazy evaluation, this is O(1) with respect to the length of the string being searched.

Splitting arrays

Kap provides two primary ways to split an array into subarrays: Partition: (type: `), z) and Partitioned enclose: (type: `, Z). Both of these functions take an array to split as its right argument, and an array on the left which indicates how the array is to be split. The two functions differ in the way they interpret the left argument.

Partition

A split happens if the value is greater than the previous value. If the value is 0 the element is skipped.

Split by increasing values:

    1 1 2 3 3 1 2 2 ⊂ "abcdefgh"
┌→──────────────────┐
│"ab" "c" "def" "gh"│
└───────────────────┘

As can be seen, a decreasing value will not cause a split.

Here’s an example of skipping elements:

    1 1 0 0 1 0 1 1 ⊂ "abcdefgh"
┌→────────────┐
│"ab" "e" "gh"│
└─────────────┘

This behaviour makes this function very useful when one has a bitmask with the groups that needs to be split. One example of such case is if you want to split a string by space:

    { (⍵≠@\s) ⊂ ⍵ } "a string separated by space characters"
┌→─────────────────────────────────────────────────┐
│"a" "string" "separated" "by" "space" "characters"│
└──────────────────────────────────────────────────┘

In the above example, the expression ⍵≠@\s returns a bitmask where any character is not a space:

    { ⍵≠@\s } "a string separated by space characters"
┌→──────────────────────────────────────────────────────────────────────────┐
│1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0 1 1 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1│
└───────────────────────────────────────────────────────────────────────────┘

This bitmask is the perfect input to .

What if we want to split on several characters? Let’s say we want to split on space, period and comma. We can take advantage of the function discussed above, and do it this way:

    { (~⍵ ∊ " ,.") ⊂ ⍵ } "a,string,separated,by, various. different.,. characters"
┌→───────────────────────────────────────────────────────────────┐
│"a" "string" "separated" "by" "various" "different" "characters"│
└────────────────────────────────────────────────────────────────┘

Partitioned enclose

The function partitioned enclose is very similar to partition, but here the array is split wherever the value is 1:

    1 1 0 1 0 0 0 1 ⊆ "abcdefgh"
┌→──────────────────┐
│"a" "bc" "defg" "h"│
└───────────────────┘