Introduction

The following document lists functions and operators available in Kap.

When describing arguments to dyadic calls in regular functions, the left argument is referred to as A and the right argument as B.

Some documentation text is sourced from APLWiki. These sections are marked with a footnote. All copyrights for those sections remain with the original authors.

Parsing and evaluation

When parsing a piece of code, such as an entire file, or a single command typed on the REPL, the process is split into two phases: Parsing and Evaluation.

During the parsing phase, the parser reads the input and processes each declaration in order. Declarations include function definitions, syntax definitions or declarations. If an error occurs during parsing, any declarations that had been processed prior to the error will remain in effect.

After the parsing phase, each statement is evaluated in order with the return value of the entire evaluation being the result of the last statement evaluated. Each statement is separated by the symbol or a newline.

After evaluating a statement, the result is collapsed (see comp) before the next statement is evaluated. The reasoning behind this is that standalone statements are generally evaluated for its side effects.

Forward declarations

Since all code is parsed prior to evaluation, the Kap parser needs to know if a symbol refers to a function or a value at the time of parsing. This means that in contrast to APL, the roles of a symbol cannot change during evaluation. The normal way to deal with this is to ensure that a function is declared before the point in the code where the function is called.

This presents a problem when two functions needs to call each other. At this point, forward declarations needs to be used.

At present, Kap does not have a dedicated syntax for forward declarations. Instead, one defines a function that will never be called for the purpose of ensuring that the symbol is defined as a function. After defining the function calling this function, it can be redeclared with its correct definition.

foo ⇐ { throw "Forward declaration" }
bar ⇐ { foo ... }
foo ⇐ { bar ... }

Syntax

Datatypes

Kap supports the following datatypes:

  • Integer

  • Floating point

  • Rational

  • Complex

  • Character

  • Map: Created using the map function. Please see more information about maps in section Maps.

  • Symbol: 'foo, 'qw:bar. If the namespace name is blank, the symbol is placed in the keyword namespace: :abcd. All keywords are self-evaluating.

  • N-tuple: zero or more values treated as a single value.

  • Array: An N-dimensional array of values, where each value is a primitive or another array.

  • Timestamp: A primitive object representing a point in time.

  • Null: The special value null that is used to describe the absence of a value.

Numbers

The different numeric types can be entered as follows:

Integer
  • Normal number: 1234

  • Negative numbers: ¯456

  • Hexadecimal: 0x12

  • Binary: 0b1100110

Internally, integers are stored as either 64-bit numbers, or as a bigint. If the result of a computation results in a value that will not fit in a 64-bit integer, it will automatically be represented as a bigint. Under normal circumstances there is no observable difference between the two internal representations, except for performance.

Rational

The result of divisions between integers always result in a rational number. If this number is not an integer, it is stored internally as a pair of bigints and displayed in the REPL in the form num/den.

To type a rational number:

  • Pair of integers: 3r2.

  • Decimal form: 10.5r

The individual parts of a rational number can be read using the functions math:numerator and math:denominator (link).

Floating point

Floating point numbers are stored as IEEE-754 double precision floating point.

To enter a floating point number:

  • Plain number: 1.234

  • Negative number: ¯0.001

  • Exponential form: 4.1e22

Complex

Complex numbers are stored internally as a pair of floating point numbers.

Complex numbers are entered by separating the real and imaginary parts using a j. For example: 100j200 for the number (100+200i).

The real and imaginary parts can be accessed using the functions math:re and math:im (link).

Characters

A character is a single Unicode codepoint. The following forms are allowed:

  • @a — Any character is allowed, except backlash

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

  • @\u0397 — Hex codepoint

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

  • @\r — CR (codepoint U+000D)

  • @\e — Esc

  • @\s — Space

  • @\t — Tab

  • @\\ — Backslash

  • @\0 — Nul character

String syntax

Strings are single-dimensional arrays of characters, enclosed in double-quotes: "foo test".

The following escape codes are allowed in a string:

  • \\ — Backslash

  • \" — Double quote

  • \n — Newline

  • \r — CR

N-tuples

N-tuples, also simply called “lists”, are primitive values that act as a container of zero or more values. The explicit list syntax uses ; to separate the elements. List parsing has lower precedence than boolean operations as well as regular lists and function calls, which means that they usually have to be enclosed in parentheses.

1;2;3;4 — A list consisting of 4 elements.
1 + 2 ; 3 + 4 ; 5 — a list consisting of the three values: 3, 7, and 5.

Note that the above syntax can only create N-tuples of length 2 or more. To create N-tuples of length 0 or 1, use the function .

Null

The value null is an atomic value which can be used to represent the absence of a value. Its datatype is kap:null, which has only a single instance.

Short-circuiting boolean operations

The names and and or are short-circuiting functions that act on the arguments true/false property. For the purposes of these functions, the numeric value 0 is considered false, and any other value is true.

io:println 2 and io:println 3 — Evaluates to 3, and will print both 2 and 3.
io:println 1 or io:println 0 — Evaluates to 1, and will not print 0.

Note that and and or has higher precedence than lists, but lower than regular arrays and function calls.

Line continuation

If a line ends with a backquote `, the subsequent newline is treated as whitespace. This allows for statements to be broken up into multiple lines.

    1 + 2 + `
    3 + 4 + 5
15

Syntactic elements

Symbols

Symbols are used to name objects in Kap. The name of a symbol consists of one or more non-space Unicode characters. Some examples include:

  • +

  • foo

  • 列表

All symbols belong to a namespace. A namespace is a grouping of symbols. When parsing a symbol, the namespace can be explicitly specified by prefixing the symbol name with the namespace name, separated by a :. Examples:

  • default:foo

  • math:sin

  • abc:bar

If the namespace is blank, it is assumed to be keyword. Any symbol in the keyword namespace acts as a variable that returns the symbol itself.

When looking up a symbol without a namespace, the symbol is searched in the following order:

  • Check if the symbol is already interned in the current namespace

  • Search all imported namespaces for an external symbol

  • Intern the symbol in the current namespace

A symbol can be marked as “single character”, in which case it will always parse as a single symbol. For example, the symbol ÷ is a single character symbol. Because of this, the sequence ÷÷ are two separate symbols, instead of a single symbol consisting of two characters.

The declaration :singleCharExported can be used to declare a symbol to be single character. See :singleCharExported for details.

: Comments

The character indicates the start of a comment. Everything until the next newline will be ignored.

: Function definition

The symbol is used to define global functions. The general form is:

∇ header {
  body
}

The last evaluated form in body is returned from the function.

The header has the following possible forms:

  • name — Declare a function named name. In body, the left argument is accessed using and the right argument using .

  • name x — The right argument is accessed using the name x. The left argument is not accessible.

  • x name y — The left argument is accessed using the name x, and the right argument has the name y.

  • (a;b) name (d;e) — The left and right arguments are assumed to be n-tuples and are destructured prior to evaluating the body.

  • (a name) x — Monadic operator deriving a monadic function.

  • x (a name b) y — Dyadic operator deriving a dyadic function.

When declaring an operator, the function arguments are passed as function objects, and needs to be applied using the function application operation: .

To declare a monadic function that returns the argument + 1:

∇ foo x {
  x+1
}

To declare an operator that adds 100 to the result of evaluating the function after adding 1 to the argument:

∇ (a foo) x {
  result ← ⍞a 1+x
  100 + result
}

: Local function declaration

The symbol is used to declare lexically scoped local functions. It has the following general form:

foo ⇐ fn

Where fn can be any function as it appears in an expression. This includes:

  • Plain functions: +

  • Function compositions: +-

  • Dfns: { body }

  • Function reference applications: ⍞name

The declared function has the normal lexical scope, which is the same as any variable declared in the same scope. Local functions also has access to any variables visible within its scope.

λ: Create function reference

The λ symbol is used to create a function reference from a function. The syntax is: λ fn where fn is any function as it appears in an expression.

The return value is a primitive value which behaves just like any primitive. It can be passed to other functions, and be members of arrays.

When creating a function reference, the function captures any lexical bindings references from within the function. These bindings remain valid even after the scope is exited.

To call a function from a function reference, use the apply symbol: . Please see the documentation for this symbol for more information.

: Apply function from function reference

The is used to call a function given its function reference. It can take any of the following forms:

  • ⍞ variable — Calls the function reference stored in variable variable.

  • ⍞(expression) — expresion is evaluated to return a function reference which is subsequently called.

Modified assignment

Modified assignment are specified using a in a position where an operator would be allowed. I.e. after a function call. A modified assignment has the following form:

Lvalue F← value

Where F can be any function call, including explicit named functions, dfns or tacit expressions. The modified assignment expression is evaluated as follows:

Lvalue ← Lvalue F value

Note that any side effects when evaluating Lvalue will only be executed once.

Parser directives

use: Load source file

Format: use("filename")

When the parser sees a use statement, the file is looked up and loaded as a separate parse unit. Any changes to the default namespace made while processing the file will be reverted once parsing of the file is complete.

import: Import symbols into current namespace

Format: import("namespace")

This statement makes all exported symbols from namespace visible in the current namespace without the need to specify the namespace explicitly.

namespace: Change default namespace

Format: namespace("namespace")

Set namespace as the default namespace for this parse unit.

declare: Declare symbol parameters

The declare statement is used to control various aspects of symbols.

:export: Declare a symbol as exported

Format: declare(:export sym)

Declares one or more symbols as exported. sym is either a single symbol or a space-separated list of symbols within parentheses, for example: (foo bar).

Symbols that are declared as exported will be accessible from the local namespace after performing an import.

:const: Declare a variable as constant

Format: declare(:const sym)

This statement indicates that sym should not be modifiable. An attempt to modify such values will raise an error.

:singleCharExported: Parse symbol as single character

Format: declare(:singleCharExported "S")

The argument S must be a single character. This statement tells the tokeniser that the given character should not form part of a word, but always be parsed as a single symbol. This allows single-symbol names to be written without needing to be delimited with spaces.

This declaration also marks the symbol as being exported.

Array indexing

Values can be retrieved from arrays various ways:

  • Bracket index: A[0;1]

  • function: see separate section: Index lookup

  • function: see separate section: Select

  • Dereference symbol: see below

Bracket index

An array can be followed by an index within square brackets. An index is specified as an n-tuple of the same size as the number of dimensions in the value. Each value in the index specification indicates which values along the corresponding axis to retrieve.

For example, to retrieve a scalar value from a 1-dimensional array:

    (10 20 30 40)[2]
30

To retrieve specific elements:

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

To retrieve a scalar value from a 2-dimensional array:

    (3 3 ⍴ ⍳9)[0;1]
1

To retrieve an entire row:

    (3 3 ⍴ ⍳9)[0;]
┌→────┐
│0 1 2│
└─────┘

To retrieve a subarray:

    (4 4 ⍴ ⍳16)[0 3;1 3]
┌→────┐
↓ 1  3│
│13 15│
└─────┘

The dimensions of the result always match the combined dimensions of the index arguments. A consequence of this is that when reading a single element from a nested array, the result is enclosed:

    ("foo" "bar")[0]
┌─────┐
│"foo"│
└─────┘

Use the function to retrieve the enclosed array.

Bracket assignment

The bracket index syntax can also be used to update a variable. A bracket index expression where the indexed value is a variable name is a valid left argument to an assignment. A new array is created that contains the elements of the original array, with the values that would have been returned from the bracket index replaced by the values to the right of the assignment.

    foo ← 4 5 ⍴ ⍳20
    foo[2;1] ← 100
    foo
┌→──────────────┐
↓ 0   1  2  3  4│
│ 5   6  7  8  9│
│10 100 12 13 14│
│15  16 17 18 19│
└───────────────┘

Note that this operation replaces the value of the variable with a new array. It does not update the old array, meaning that any other references to the old array will not see its content changed.

Negative indexes

In most places where array positions are specified using an integer index, a negative value can be used to index from the end of the given axis, where ¯1 refers to the last element, and -≢A refers to the first element.

Dereference operation

The . symbol can be used to dereference an element in a hashmap or an array.

The symbol used in not an operator or a function but rather a syntactic element which ensures evaluation from left-to-right. This makes the feature particularly useful for resolving elements in tree structures, such as the form returned after parsing JSON data.

Assuming the file file contains the following JSON content:

{ "foo": ["test", "xyz"] }

And then running the following code:

json ← json:read "file"
a ← json.("foo").(0)

After this, the variable a will contain the value "test".

The different forms allowed in array dereferencing are explained below:

Hashmap lookup with symbol key

This has the form M.symbol where M is a hashmap.

  • M.foo — Equivalent to ⊃M['foo]

  • M.ns:foo — Equivalent to ⊃M['ns:foo]

  • M.:foo — Equivalent to ⊃M[:foo]

Hashmap lookup with expression key

This looks up a value in a hashmap using any expression as a key.

  • M.(expr) — Equivalent to ⊃M[⊂expr]

Array lookup using expression

Given any array An for an n-dimensional array, one can look up an array element by specifying index coordinates using a dereference argument within parenthesis:

  • A1.(1) — Equivalent to ⊃A1[1], i.e. return the second element of the array

  • A2.(0 2) — Equivalent to ⊃A2[0;2], i.e. return the element at row 0, column 2.

  • A2.(1) — Raises a dimension error since the size of the index does not match the rank of the left argument.

N-tuple lookup using expression

If N is a tuple, the same syntax as when using arrays can be used to dereference individual elements of the N-tuple:

  • N.(0) — Equivalent to ⊃(⌷ N)[0]

Quad variables

Kap provides a set of special variables. These variables start with a symbol. The following quad variables are currently available:

⎕a — Lowercase ASCII letters

This variable contains the following string: "abcdefghijklmnopqrstuvwxyz"

⎕A — Uppercase ASCII letters

This variable contains the following string: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

⎕d — Standard decimal digits

This variable contains the following string: "0123456789"

⎕argv — Argument list

This variable contains an array of strings representing the arguments given to the interpreter when it was started.

Scalar functions

All scalar functions are evaluated in the same way. For monadic invocations, the return value has the same shape as the argument, with the function being recursively applied to any non-primitive element in the input array.

For dyadic invocations, both arguments must have the same dimensions, or at least one of the arguments must be a scalar. If the arguments have matching dimensions, the operation is applied pairwise. If one of the arguments is a scalar, that scalar is applied together with each element in the other argument.

When performing scalar operation between different numeric types, the standard conversion rules apply, unless documented to do something different. The rules are iterated from top to bottom, stopping after the first match:

  • Any argument is complex - Complex

  • Any argument is floating point - Floating point

  • Any argument is rational - Rational

  • Both arguments are integer - integer

  • Both arguments are character - Character

  • Raise an error

+: Add/Conjugate

Monadic: Conjugate

When called monadically, + performs the complex conjugate operation. This operation reverses the sign of the imaginary part. For real numbers, the operation simply returns the argument.

+22

Dyadic: Add

When called dyadically, this function adds the two arguments. If one of the arguments is a character, the other argument must be a real number which is truncated to an integer and added to the Unicode value of the character, returning a new character.

1+45
0.0+55.0
1j2 + 6j77.0J9.0
@f + 1@g

-: Subtract/negate

Monadic: Negate

Negate the argument.

-2¯2
-(¯2)2
-4j9-4.0J-9.0

Dyadic: Subtract

Subtract B from A.

8-17

Subtracting a character from another character will return the difference between taking the Unicode codepoint into consideration. The most useful use of this is to subtract the nul symbol, @\0, from a character to obtain the Unicode codepoint as an integer: @a - @\0 returns 97.

×: Multiply/angle

Monadic: Angle

For real values, return the values 1, 0 or -1 if the argument is positive, zero or negative respectively. For complex arguments, return a value with magnitude 1 having the same angle.

×21
ׯ4-1

Dyadic: Multiply

Multiply A with B.

÷: Divide/reciprocal

Monadic: Reciprocal

Return the reciprocal of the argument.

Dyadic: Divide

Divide A with B.

|: Mod/magnitude

Monadic: Magnitude

Returns the magnitude of the argument. For real numbers, this is simply the absolute value. For complex numbers, it’s the length of the vector from the origin to the value.

|33
|¯44

Dyadic: Modulo

Returns the value of B mod A. Note that the order of the arguments is reversed compared to the similar function in most programming languages.

2|51

: Power

Monadic: Power

Return e to the power of the argument.

Dyadic: Power with base

Return A to the power of B.

: Log

Monadic: Natural logarithm

Return log(A).

Dyadic: Log base A

Return the base A logarithm of B.

=: Equals

Monadic: Classify

Return a 1-dimensional array of the same size as the major axis of the argument. The result maps a number to each element in the input, where all elements mapped to the same number are the same.

Dyadic: Equals

Return 1 if A and B are equal, otherwise return 0.

Note that this function is a scalar function, meaning that arrays are compared element-wise. To compare arrays for equality, use .

10=101
10=110
1 2 3 = 1 3 41 0 0

: Not equals

Monadic: Unique mask

Returns a 1-dimensional boolean array with the same size as the major axis of the argument. Each value is 1 if the corresponding major element has not occurred in the list prior to this point. If the same element has been seen, the value is 0.

Example:

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

Dyadic: Not equals

Return 1 if A and B are not equal, otherwise return 0.

Note that this function is a scalar function, meaning that arrays are compared element-wise. To compare arrays , use .

10≠111
3 3 4 4 ≠ 4 4 4 30 0 1 0

<: Less than/increase rank

Monadic: Increase rank

When called monadically, this function performs the non-scalar operation “increase rank”. This function resizes the argument to a new array with a new dimension of size 1 added as an initial dimension.

The functionality is equivalent to (1,⍴A) ⍴ A

Dyadic: Less than

Return 1 if A is less than B.

Note that this function is a scalar function, meaning that arrays are compared element-wise. To compare arrays, use cmp.

>: Greater than/decrease rank

Monadic: Decrease rank

When called monadically, this function performs the non-scalar operation “decrease rank”. This function removes the major axis from the argument, and resizes the next axis to be the size of the first two axes multiplied together.

In other words, this function performs the following operation: ((×/2↑⍴A),2↓⍴A) ⍴ A for arrays of 2 or more dimensions. When called on arrays of 1 or 0 dimensions, this function returns its argument.

Dyadic: Greater than

Return 1 if A is less than B.

Note that this function is a scalar function, meaning that arrays are compared element-wise. To compare arrays, use cmp.

: Less than or equal

Dyadic: Less than or equal

Return 1 if A is less than or equal to B.

Note that this function is a scalar function, meaning that arrays are compared element-wise. To compare arrays, use cmp.

: Greater than or equal

Dyadic: Greater than or equal

Return 1 if A is greater than or equal to B.

Note that this function is a scalar function, meaning that arrays are compared element-wise. To compare arrays, use cmp.

: Logical and

Monadic: Sort up

Please see Sorting

Dyadic: Logical and

Returns 1 if A and B are 1. If the arguments are not 0 or 1, raise an error.

0∧10
1∧0 1 0 00 1 0 0
1∧@a ⇒ Error: Invalid type
0∧3 ⇒ Error: Only 0 and 1 are allowed arguments

Compatibility note: APL uses ∧ to represent the least common multiple (LCM) operation. This function is available in Kap as math:lcm.

: Logical or

Monadic: Sort down

Please see Sorting

Dyadic: Logical or

Returns 1 if either A or B are 1. If the arguments are not 0 or 1, raise an error.

0∨00
1∨11

Compatibility note: APL uses ∨ to represent the greatest common divisor (GCD) operation. This function is available in Kap as math:gcd.

: Logical nand

Dyadic: Logical nand

Returns 0 if A and B are 1, otherwise return 1. This function is equivalent to ~A∧B.

: Logical nor

Dyadic: Logical nor

Returns 0 if either A or B are 1, otherwise return 1. This function is equivalent to ~A∨B.

~: Logical not/Without

Monadic: Logical not

Returns 1 if the argument is 0, and vice versa. If the argument is not 0 or 1, raise an error.

Dyadic: Without

This is a non-scalar function. Returns A with all instances in B removed.

1 2 3 4 5 6 ~ 3 61 2 4 5

: Square root

Monadic: Square root

Computes the square root of the argument.

Dyadic: Root of base

Computes the A root of B.

: Min/Floor

Monadic: Floor

Returns the largest integer which is less than or equal to the argument.

Compatibility note: This function is not defined for complex numbers. To access the APL-compatible complex floor operation, use floorc.

Dyadic: Min

Returns the smallest of A and B.

: Max/Ceiling

Monadic: Ceiling

Returns the smallest integer which is greater than or equal to the argument.

Compatibility note: This function is not defined for complex numbers. To access the APL-compatible complex ceiling operation, use ceilc.

Dyadic: Max

Returns the largest of A and B.

!: Binomial/Gamma

Monadic: Gamma

Computes the result of the gamma function on A.

Dyadic: Binomial

Computes the result of the binomial function on A and B.

Object comparison functions

: Compare equal/depth

Monadic: Depth

Returns the depth of the argument. The depth is defined as being the largest number of recursively nested arrays.

≡(1 2 3) (4 5 6) (7 8 (9 10))3
≡20

Dyadic: Compare equals

Returns 1 if A and B are equal. For arrays, this means that both arrays have the same shape, and each element in A also compares equal to the same element in B.

: Compare not equals/size of major axis

Monadic: Size of major axis

Return the size of the first dimension. This is equivalent to ↑⍴A.

≢ 3 ⇒ 0
≢ 1 2 3 ⇒ 3
≢ 3 5 ⍴ ⍳15 ⇒ 3

Dyadic: Compare not equals

Returns 1 if A and B are not equal.

cmp: Compare

Dyadic: Compare

Compare A and B. Returns -1 if A is less than B, 0 if they are equal or 1 if A is greater than B.

Structural functions

Structural functions are generally defined to be any function that does not obey the general roles of scalar functions. Their return values may have a very different structure than its argument.

: Shape/Reshape

Monadic: Shape

Return the shape of the argument. The return value is an array containing the size of each dimension.

Example:

    a ← 3 4 5 ⍴ ⍳60
    ⍴a
┌→────┐
│3 4 5│
└─────┘

Dyadic: Reshape

Reshapes B into the dimensions specified by A. The resulting array with have ×/A elements. If the total number of elements in A is less than that of B, the extra elements will be dropped. If the total number of elements in A is greater than that of B, the values will wrap around to fill the result array.

If B is scalar, every element of the resulting array will have this value.

Example:

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

One of the values in A can be computed. A computed value is provided by specifying one of the following keyword instead of a size:

  • :match — The size of B must be divisible by the size of the remaining values in A. Alternatively, the value ¯1 can be used.

  • :fill — The resulting size will be large enough to fit all the values in B, with the fill element of B used if there are not enough elements to populate the resulting array.

  • :truncate — The resulting size will be as large as possible to fill the result array, possibly dropping elements in B.

  • :recycle — The resulting size will be large enough to fit all the value in B, repeating elements from B if needed.

When using :match, it is an error if the sizes don’t match:

    3 :match ⍴ 1 2 3 4
Error at: 1:10: ⍴: Invalid size of right argument: 4. Should be divisible by 3.

With :fill, all the values are used, and the fill element is used to extend the resulting array if needed:

    3 :fill ⍴ 1 2 3 4
┌→──┐
↓1 2│
│3 4│
│0 0│
└───┘

: Index generator/Index of

Monadic: Index generator

If the argument is a scalar integer, generate a 1-dimensional array of A numbers from 0 to A-1.

If the argument is an array of integers, generate an array with the shape given by the values of A, where each element is the coordinates of the respective cell.

Examples:

    ⍳3
┌→────┐
│0 1 2│
└─────┘
    ⍳2 2 5
┌┌→──────────────────────────────────────┐
│↓┌→────┐ ┌→────┐ ┌→────┐ ┌→────┐ ┌→────┐│
│││0 0 0│ │0 0 1│ │0 0 2│ │0 0 3│ │0 0 4││
││└─────┘ └─────┘ └─────┘ └─────┘ └─────┘│
││┌→────┐ ┌→────┐ ┌→────┐ ┌→────┐ ┌→────┐│
│││0 1 0│ │0 1 1│ │0 1 2│ │0 1 3│ │0 1 4││
││└─────┘ └─────┘ └─────┘ └─────┘ └─────┘│
│├→──────────────────────────────────────┤
│↓┌→────┐ ┌→────┐ ┌→────┐ ┌→────┐ ┌→────┐│
│││1 0 0│ │1 0 1│ │1 0 2│ │1 0 3│ │1 0 4││
││└─────┘ └─────┘ └─────┘ └─────┘ └─────┘│
││┌→────┐ ┌→────┐ ┌→────┐ ┌→────┐ ┌→────┐│
│││1 1 0│ │1 1 1│ │1 1 2│ │1 1 3│ │1 1 4││
││└─────┘ └─────┘ └─────┘ └─────┘ └─────┘│
└└───────────────────────────────────────┘

Dyadic: Index of

Return an array of the same shape of B. For each value in B, the result array will contain the index of this value in A. If the value does not exist in A, the result will contain the value ≢A (i.e. one greater than the last valid index in the array).

: Identity/Right

Monadic: Identity

Returns the argument itself.

⊢123123

Dyadic: Right

Returns the right argument

1⊢22

: Hide/Left

Monadic: Hide

Forces evaluation of its argument to ensure that all side effects are called and in the correct order. Then returns an empty 1-dimensional array with null fill value. This value will not be printed in the REPL, making this function useful when the side effects of an expression are desired, but there is no need to print the results.

Dyadic: Left

Returns the left argument

1⊣21

: List to array/Index lookup

Monadic: List to array

Given an N-tuple, return a 1-dimensional array with its content.

Index lookup

The result of A⌷B is an array formed with items of B extracted by the index specification A. The left argument A must be a vector whose length equals the rank of the right argument Y and depth does not exceed 2. Each element of A selects one or more indices over the corresponding axis of the right argument Y. The result is identical to that of bracket indexing in that A[X1;X2;…;Xn] ≡ X1 X2 … Xn⌷B. The resulting shape equals the concatenation of the shapes of each element of A. [1]

: Enclose/Partition

Monadic: Enclose

For non-primitive values, return a 0-dimensional array containing the argument as its value. For primitive values, the value itself is returned.

Dyadic: Partition

Both arguments must be 1-dimensional arrays. A must be as array of integers. The function splits B at the locations where the corresponding value in A is greater than the previous value. If the value in A is 0 the value in B is ignored.

1 2 2 0 1 1 ⊂ "abcdef"
┌→────────────┐
│"a" "bc" "ef"│
└─────────────┘

: Disclose/Pick

Monadic: Disclose/Mix

If the argument is enclosed (i.e. an array of rank 0), the function returns the array element:

    x ← ⊂"abc"
    ⊃ x
"abc"

Note that disclose on an atom will always return the value itself.

If is called on an array of rank 1 or greater, it performs the standard APL mix operation. If the lengths of the subarrays don’t match, the resulting array will have the size of the largest subarray, with the shorter ones filled in with the default element of the array (normally 0).

    ⊃ (1 2 3) (6 7 8 9 10)
┌→─────────┐
↓1 2 3 0  0│
│6 7 8 9 10│
└──────────┘

Dyadic: Pick

Pick an element from B based on the specification in A. The left argument can be seen as a chain of coordinates to find an element in a (possibly nested) array. In its simplest form, it can be used to pick out a single element from a single-dimensional array:

    2 ⊃ 10 11 12
12

If more than one value is given, it is used to recursively find nested array elements:

    1 2 ⊃ (1 2 3) (4 5 6)
6

If the array being searched has more dimensions, one provides the full coordinates instead of just single elements:

    (1 0) 1 ⊃ 2 2 ⍴ (1 2 3) (4 5 6) (7 8 9) (10 11 12)
8

,: Concatenate/Ravel

Monadic: Ravel

Return a new array containing the same values as the argument, but reshaped to a single dimension.

Dyadic: Concatenate

Concatenates A with B along the last axis.

A special case exists when one of the arguments is a one-dimensional array with zero elements. In this case, the other array is returned regardless of its dimension. I.e. for these arrays, there is no need for the argument dimensions to conform.

: Concatenate first axis/Table

Monadic: Table

Reshape the argument into a 2-dimensional array. SFor a 1-dimensional argument, the resulting array will have dimension (≢A) 1. For arguments of higher dimension, the resulting shape will be (≢A),×/↓⍴A.

Dyadic: Concatenate first axis

This function behaves the same as , except that the default axis is 0.

: Singleton/Pair

Monadic: Singleton

Creates a 1-dimensional array of size 1, containing the argument. This function is the same as ,⊂.

Dyadic: Pair

Creates a 1-dimensional array of size 2, where the first element is A and the second element is B. This function is the same as ,⍥⊂.

: Take/Take first

Monadic: Take first

Returns the first element in the argument. If the argument is a scalar value, return the argument itself.

    ↑ 10 11 12
10

Dyadic: Take

Take some number of values from each axis. A is an array of integers whose length is less than or equal to the rank of B. For each axis, the corresponding value in A represents the number of values to take from the start of that axis, if the value is negative, the absolute of the value is computed and that number of values is taken from the end of the axis. The value can also be null, in which case the size of the corresponding axis is used.

If the length of A is less than the rank of B, all values are taken from the remaining axes.

    2 3 4 ↑ 5 5 5 ⍴ ⍳125
┌┌→──────────┐
│↓ 0  1  2  3│
││ 5  6  7  8│
││10 11 12 13│
│├→──────────┤
│↓25 26 27 28│
││30 31 32 33│
││35 36 37 38│
└└───────────┘

Using null size:

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

: Drop/Drop first

Monadic: Drop first

Removes one row from the major axis of an array. This is equivalent to calling dyadic drop with an argument of 1.

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

Dyadic: Drop

Drop some number of values from each axis. A is an array of integers whose length is less than or equal to the rank of B. For each axis, the corresponding value in A represents the number of elements to drop from the beginning of the axis, or, if the value is negative, the absolute of the value represents the number of elements to drop from the end of the axis.

If the length of A is less than the rank of B, the remaining values are set to 0.

?: Roll/Deal

Monadic: Roll

The scalars in the argument array must be an integer equal to or greater than zero. For any 0 in the input, a random floating-point value between 0 (inclusive) and 1 (exclusive) is returned. For any value greater than zero, a random integer between 0 (inclusive) or the value (exclusive) is returned.

Dyadic: Deal

Return A random numbers below B without duplicated values. Both A and B must be greater than zero, and A must be less than or equal to B. From this follows that if A and B are the same value, this function returns a random permutation of the numbers 0 to B (exclusive).

: Rotate horizontally/Reverse horizontally

Monadic: Reverse horizontally

Reverse the order of the elements along the last axis. With an axis argument, reverse along that axis.

Example:

    ⌽ ⍳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│
└─────────┘

Dyadic: Rotate horizontally

Rotate the values in the array the given number of steps to the left.

Example:

    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│
└───────────────────────────────────────────────────────────┘

: Rotate vertically/Reverse vertically

Monadic: Reverse vertically

This function behaves the same as , with the difference being that the default axis is axis 0.

Dyadic: Rotate vertically

This function behaves the same as , with the difference being that the default axis is axis 0.

: Transpose/Transpose by axis

Monadic Transpose reverses the axes of the right argument. When applied to a 2-dimensional array, the result is its transpose. Scalar and 1-dimensional arguments are unaffected. [1]

Compatibility note: APL supports repeated axis in the left argument. This is not supported in Kap.

: Member

Monadic: Enlist

Recursively find all atomic values in the argument and return them as a single-dimensional array.

    ∊ (1 2) (3 4) (5 6 7 (8 9))
┌→────────────────┐
│1 2 3 4 5 6 7 8 9│
└─────────────────┘

If an axis parameter is given, the value indicates the maximum level on which the enlist operation will act. Example:

    ∊[1] ((1 2) (3 4)) 5
┌→────────────┐
│┌→──┐ ┌→──┐ 5│
││1 2│ │3 4│  │
│└───┘ └───┘  │
└─────────────┘

Dyadic: Member

Returns an array of the same shape as A. For each value in A, the corresponding value in the returned array is set to 1 if the value is found in B, otherwise, set it to 0.

: Find

Both arguments can be arrays of any shape. The entire left argument is tested against each position in the right argument. The result is a boolean array having the same shape as the right argument, where a 1 indicates the position of the first element of the matched subarray (which can be seen as the "leftmost" or "top left" position in case of a vector or matrix). If the left argument has lower rank, it is treated as if the shape is prepended with ones. If the left argument has higher rank, Find does not error, but it is never found in the right argument (resulting in an all-zero array). [1]

: Grade up

Grade up returns a permutation vector whose length equals the number of major cells, so that indexing into the argument gives the sorted array. The resulting array is sorted in increasing order.

Grade performs stable sorting, so that the indices of the repeated major cells are sorted by the order of appearance. Because of this, Grade Down produces the reverse of Grade Up only if all the major cells are unique. [1]

: Grade down

This function performs the same operation as except that the array is sorted in decreasing order.

/: Replicate

The replicate function copies each element of the right argument a given number of times, ordering the copies along the last axis by default. If provided, the axis argument specifies along which axis the operation should be performed. Replicate is a widely-accepted extension of the function Compress, which requires the number of copies to be Boolean: each element is either retained (1 copy) or discarded (0 copies). Replicate with a Boolean left argument or operand may still be called “Compress”. [1]

: Replicate first

This function is the same as /, except that it performs the operation along axis 0.

: Format

Monadic: Format

Returns a string representation of the argument.

Dyadic: Format with pattern

Format the values in B according the pattern string in A and returns the formatted string. Any characters in the pattern is written as-is, with $ indicating a control code which consists of a number of comma-separated arguments followed by a character that indicates the operation to be performed.

  • $ — output a plain $

  • s — output the next argument as a string. A single numeric argument is allowed which specifies the width of the output, with padding to the left. If the argument is negative, padding is to the right.

Examples:

    "ab$5sx" ⍕ 12
"ab   12x"
    "ab$¯5sx" ⍕ 12
"ab12   x"
    "ab$¯5sx$syz" ⍕ 12 38
"ab12   x38yz"

: Parse number

Monadic: Parse number

Given a string, attempt to parse it as a number. Raises an error if the parsing failed.

%: Case

Dyadic: Case

This function accepts an array of indices and a list of arrays, each with the same shape as the index array, and for each cell in the index, pick a corresponding value in one of the subarrays. Example:

    0 1 1 2 % "abcd" "1234" "defg"
"a23g"

The first cell in the left argument is 0, so it picks the first element of the first array in the right argument. The second cell is 1, so the second value is picked from the second array, and so on.

: Partitioned enclose/Nest

Monadic: Nest

Dyadic: Partitioned enclose

Both arguments must be 1-dimensional arrays. A must be as array of integers. The function splits B at the locations where the value in A is 1.

    1 0 0 0 1 1 ⊆ "abcdef"
┌→─────────────┐
│"abcd" "e" "f"│
└──────────────┘

: Select

A must be an array of coordinates specifying values in B. Each coordinate must be an array with the same size as the rank of B (they may also be scalar, if B is 1-dimensional). The result is an array with the same dimension as A containing the specified values in B.

    2 2 5 2 ⊇ "abcdef"
"ccfc"

: Group

Dyadic: Group elements by index

A is a 1-dimensional array of integers, with length equal to the tally of B. The result is a nested vector containing major cells of B, in the positions marked by corresponding entries in B. Cells that correspond to a negative number are dropped from the result.

: Where/Interval Index

Monadic: Where

Given an array of positive integers, return an array of values indicating the indexes where any nonzero elements exist. Values are repeated the number of times indicated by the corresponding integer. As a special case, when passed a boolean array, the result is an array indicating the positions of any 1’s:

    ⍸ 0 1 0 0 0 1 1 0 0
┌→────┐
│1 5 6│
└─────┘

In the general case, values are repeated:

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

If the argument has higher rank, each element is a nested array indicating the position of the value in the array:

    ⍸ 3 3 ⍴ 0 1 0 1 1 0 1 1 1
┌→──────────────────────────────────┐
│┌→──┐ ┌→──┐ ┌→──┐ ┌→──┐ ┌→──┐ ┌→──┐│
││0 1│ │1 0│ │1 1│ │2 0│ │2 1│ │2 2││
│└───┘ └───┘ └───┘ └───┘ └───┘ └───┘│
└───────────────────────────────────┘
Inverse: Histogram

The inverse of is also referred to as the histogram function. It It accepts a sorted array of integers, and returns an array where, for each index in the resulting array, the value at that index indicates the number of times that value was found in the input.

    ⍸˝ 2 2 2 2 3 5 5 5 6 7
┌→──────────────┐
│0 0 4 1 0 3 1 1│
└───────────────┘

Dyadic: Interval Index

A is a scalar or 1-dimensional sorted array which is strictly increasing. These values define a set of intervals, defined as the first interval starting with all values up to (but not including) the first value in the array. The next interval begins at exactly the first element up to the next, and so on. The return value has the same shape as B, where each value is an integer, specifying which interval the value belongs to.

Example:

    4 8 ⍸ 0 3 4 5 10 11
┌→──────────┐
│0 0 1 1 2 2│
└───────────┘

: Unique/Union

Monadic: Unique

Return an array of all unique elements in the argument.

Dyadic: Union

Return the union of the elements in the arguments. Values that are present in both arguments will only be included once.

: Encode

Encode computes the representation of the right argument in the radix system defined by the left argument. Encode is the inverse of Decode ⊥ with the same left argument A, when A is a 1-dimensional array. [1]

If the left argument is a scalar integer, the result will be computed as if that value was repeated to the required length to fit the entire value.

: Decode

Decode evaluates the right argument in terms of the radix system defined by the left argument. Decode is the inverse of Encode ⊤ with the same left argument A, when A is a vector and the right argument is a valid representation of a number in the radix system defined by A. [1]

: Intersection

Returns the intersection of A and B. The result is an array of all elements that are present in both arrays.

: Key

The Key function is used to group a set of values based on some set of keys.

A is an array containing keys, and B is an array of the same size that holds the values. The result is an n-by-2 array where n is the number of unique keys. For each row, column 0 contains the key, and column 1 contains an array of all values with the corresponding key. Example:

    2 1 3 2 2 1 1 ⌸ "foo" "bar" "xyz" "abcdef" "xz" "ab" "ac"
┌→──────────────────────┐
↓2 ┌→──────────────────┐│
│  │"foo" "abcdef" "xz"││
│  └───────────────────┘│
│1     ┌→──────────────┐│
│      │"bar" "ab" "ac"││
│      └───────────────┘│
│3               ┌→────┐│
│                │"xyz"││
│                └─────┘│
└───────────────────────┘

: Matrix division

Monadic: Matrix inverse

Return the inverse of a matrix

Dyadic: Matrix division

Divide the matrix A with B.

: Range

Dyadic: Expand to a range of integers

In its simplest form, when given integers A and B, the expression A … B returns a sequence of numbers from A to B. For example: 20 … 23 returns the array 20 21 22 23. If B is less than A, the resulting sequence will be decreasing.

If A or B are arrays, the values used to generate the sequence are the last element of A and the first element of B. The remaining elements will form the prefix and suffix of the resulting array. Example:

    100 200 5 … 8 300 400
┌→──────────────────────┐
│100 200 5 6 7 8 300 400│
└───────────────────────┘

The range function also supports character ranges. If the start and end values are characters, then the result is the range of Unicode characters between the given codepoints:

    @a … @z
"abcdefghijklmnopqrstuvwxyz"

Specialised functions

: Create list

Create an N-tuple. The function returns an N-tuple containing the elements of the input array.

labels: Assign or read axis labels

The labels function is used to programmatically manage the axis labels for a given array. Once assigned, the labels will be preserved by certain functions that preserve the general structure of an array. Such functions include take, drop, reverse, etc. The idea is that the axes in the return value for these functions can be interpreted to be the same as the ones in the input.

Axis labels are used by the charting functions to label values. They are also used by the array editor to display the names of the columns and rows.

Monadic: Read axis labels

Return the labels for the given axis. The axis is specified as an axis argument to the function:

    labels[0] "abc" "def" "ghi" labels[0] 3 3 ⍴ ⍳9
┌→────────────────┐
│"abc" "def" "ghi"│
└─────────────────┘

If no labels are assigned to an axis, a list of empty arrays are returned:

    labels[0] "abc" "def" "ghi" labels[1] 3 3 ⍴ ⍳9
┌→────┐
│⍬ ⍬ ⍬│
└─────┘

Dyadic: Assign axis labels

Given an N-dimensional array B, calling labels[M] with M being a valid axis for B, return a new array where the labels for axis M is set to A. A must be a single-dimensional array of the same size as the selected dimension in B.

comp: Force evaluation of lazy values

Collapses a possibly lazy array and evaluates all values. The return values are guaranteed to be a self-contained array with no references held to any other objects. Reading from this array will not cause concurrency issues.

close: Generic close function

This function is used to close any stateful object. The main such object is the SQL connection objects and SQL prepared statements.

atLeave: Call a function when leaving the current lexical scope

NOTE: The syntax for this operator is not fixed, and may change syntax in the future, if a nicer syntax is suggested.

This is a monadic operator that derives a monadic function. When called, this function will register the operator argument to be called once execution leaves the current scope. Example:

{
  {io:println "Leaving scope: " ⍵} atLeave 2
  io:println "In scope"
} 0
io:println "Outside function scope"

This will print the following:

In scope
Leaving scope: 2
Outside function scope

This operator is typically used when using resource objects that needs to be closed when completed. For example, to ensure that SQL connections are closed, use the following:

conn ← close atLeave sql:connect "connection string"

Operators

¨: For each

The given function is applied to the arguments and returns an array of the same shape as the input.

Assuming F is a function:

F¨ 1 2 3 is equivalent to (F 1) (F 2) (F 3)

10 20 30 F¨ 1 2 3 is equivalent to: (10 F 1) (20 F 2) (30 F 3).

Lazy behaviour: The result of ¨ is a lazy array. The function will only be called when the underlying value is retrieved. Note that the result is not cached, so if a result is retrieved more than once, the function will be called once for each time the value is read. If multiple reads are expected it is recommended to collapse the array prior to reading it.

/: Reduce

Monadic: Reduce

Format: F[axis]/ x where F is a function, x is an array and axis is an optional axis specifier. The axis specifier defaults to the last axis if not specified.

If x is a one-dimensional array, the / operator acts as a simply left-reduction. In other words, the following expression:

+/ 1 2 3 4

Results in the following computation (where the variables tN are temporary and not visible externally:

t0 ← 1+2
t1 ← t0+3
t1+4

When the argument has a higher dimension, the result array is reduced to the same shape, but with the selected axis removed. For example, given a 3-dimensional array of shape 2 3 4, the resulting array after reducing along axis 2 will be 2 3.

When reducing a higher dimension array, the reduction always takes place along the selected axis, with actual operations performed as per the description above.

Compatibility note: If the input array has rank 1, the result will not be enclosed. This is different from most APL implementations. The function behaves like APL.

Lazy behaviour: The result of a reduction is a lazy array. The computation will only happen when the result is requested.

Dyadic: Windowed reduce

This operator reduces each overlapping "window" in its right argument of the size given by its left argument.

When applied to a 1-dimensional argument, n f/x evaluates to the expression (a f b f c) (b f c f d) … where a, b, c, d, … are the elements of A, grouped into windows of size n. It works like Reduce, except applied on overlapping segments of an array, and borrows most of its functionality from it. When n is negative, each window is reversed before the reduction is done.

The magnitude of n must be no more than 1 greater than the size of x along the relevant axis. [1]

: Reduce leading axis/Windowed reduce leading axis

Monadic: Reduce leading axis

This function behaves the same as / with two differences:

  • The axis specifier will default to 0 rather than the last axis.

  • If the input array is rank 1, the result will be enclosed (this is the standard behaviour in most APL implementations)

Dyadic: Windowed reduce leading axis

This function behaves the same as / with the only difference being that the axis specifier will default to 0 rather than the last axis.

: Outer product

Format: x F⌻ y where F is a dyadic function.

This operator derives a dyadic function that returns an array consisting of all combinations of the elements of the last axis of x with the elements of the leading axis of y.

For one-dimensional arrays, this corresponds to a table mapping each element of x to each element of y:

    1 2 3 ,⌻ 1000 2000 3000
┌→─────────────────────────┐
↓┌→─────┐ ┌→─────┐ ┌→─────┐│
││1 1000│ │1 2000│ │1 3000││
│└──────┘ └──────┘ └──────┘│
│┌→─────┐ ┌→─────┐ ┌→─────┐│
││2 1000│ │2 2000│ │2 3000││
│└──────┘ └──────┘ └──────┘│
│┌→─────┐ ┌→─────┐ ┌→─────┐│
││3 1000│ │3 2000│ │3 3000││
│└──────┘ └──────┘ └──────┘│
└──────────────────────────┘

: Inner product

The Kap implementation of inner product is compatible with that of APL, with the difference being that the middle dot symbol is used instead of a period.

: Commute/duplicate

Monadic: Duplicate

Format: F⍨ x

Derives a monadic function that calls F dyadically with x as arguments.

+⍨ 1020

Dyadic: Commute

Format x F⍨ y

Derives a function which calls the underlying function with the arguments reversed.

10-⍨1-9

: Power operator

A call to the power operator is of the form A (f⍣g) B, where

  • A is an optional argument.

  • f is a function. If A is given, then it is bound to f so A (f⍣g) B is equivalent to ((A f)⍣g) B.

  • g can be an array or a function.

The power operator repeatedly applies f to Y based on the type of operand g:

  • Function: Must be dyadic and must return a boolean singleton. The previous iteration value is provided as the right argument to f, and the current iteration value is given as the left argument. f is repeatedly applied until this function returns 1.

  • Integer: g specifies the number of times f should be applied on B.

\: Scan

The scan operator is similar to reduce, with the difference that the intermediary results are preserved.

Compatibility note: Like the reduce operator, the calculation is performed left-to-right, accumulating the result from each function invocation in order. This behaviour is different from APL which defines scan as a right-to-left reduce on each prefix. The Kap implementation is similar to that of BQN and J.

    +\ 1 2 3 4
┌→───────┐
│1 3 6 10│
└────────┘

: Scan first axis

This operator is the same as scan, except that it scans along the first axis by default.

: Rank operator

The right operand specifies the rank of subarrays to which the left operand function is applied as follows: For left argument ⍺ and right argument ⍵,

⍤    c   ⍝ Rank-c cells of ⍵ (monadic) or both arguments (dyadic)
⍤  b c   ⍝ Rank-b cells of ⍺ and rank-c cells of ⍵ (dyadic)
⍤a b c   ⍝ Rank-a cells of ⍵ (monadic), b-cells of ⍺ and c-cells of ⍵ (dyadic)

A non-negative right operand specifies the number of final axes to which the function applies. A negative right operand specifies complementary rank, i.e. the number of leading axes to be excluded. Negative rank can also be thought of as rank specification relative to the overall rank of the argument array. [1]

: Derive bitwise

Derives a version of the underlying function which performs its operation on the individual bits of an integer. The following bitwise operations are implemented:

  • +: xor

  • -: xor

  • : xor

  • =: xnor

  • ×: and

  • : and

  • : or

  • : nand

  • : nor

  • : bitwise less than or equal

  • : bitwise greater than or equal

  • <: bitwise less than

  • >: bitwise greater than

  • : number of bits required to store the integer value, excluding any sign bit

  • : count bits

  • ~: not

  • : logical shift

Example:

5 +∵ 36

: Parallel

The parallel operator derives a new function that performs a parallel version of the function it is applied to. The exact behaviour of the derived function depends on the specific underlying function.

Currently, this operator can only be applied to ¨ (each). In this case, the result is computed split into separate tasks that are executed in parallel. The number of tasks run in parallel is equal to the number of CPU cores on the system.

Example:

foo¨  1 2 3    ⍝ Evaluate foo on each value one by one
foo¨∥ 1 2 3    ⍝ Evaluate foo for all the values in parallel

Note: The function that is called must be pure. I.e. it must not have any side effects. If the function has side effects, unpredictable results may be seen.

˝: Inverse

Derives the functional inverse of the argument function. Generally, the inverse of a function is a function that satisfies the following: F F˝ x = x. For dyadic invocations, the equivalence is: x F x F˝ y = y.

In plain language, the call F˝ x can be seen as answering the question: “what value z can I pass to F such that F z returns x?” Likewise, the dyadic call x F˝ y can be seen as answering the question: “what value z can I pass to x F z that will return y?”

The equivalence rule explained above is not strictly adhered to, but rather the implementations of the inverse functions are driven by practicality. If a specific inverse makes more practical sense, then that is implemented even if the implementation isn’t a strict inverse.

10×˝2.00.2

: Conditional null

This operator derives a function which, when called, checks if the right argument is null. If it is, returns null. Otherwise calls the original function with the arguments as passed to the derived function. This is useful when looking up values in hashmaps.

    1 2 +⍰ 100 200
┌→──────┐
│101 202│
└───────┘
    1 2 +⍰ null
null

Compositional operators

: Compose

  • x A∘B y is evaluated as x A (B y)

  • A∘B y is evaluated as y A (B y)

: Inverse compose

  • x A⍛B y is evaluated as (A x) B y

  • A⍛B y is evaluated as (A y) B y

: Over

The over operator derives a function which, when called dyadically, calls the right function on both arguments individually and then calls the left function on the results. In other words, this operator can be thought of processing the arguments using A before acting on it using B.

  • x A⍥B y is evaluated as (B x) A (B y)

  • A⍥B y is evaluated as A B y

: Structural under

The structural under operator takes two functions: When called as A⍢B x, the function B is first called on x, and the return value is passed to A. The effect of B is then reversed.

For inversible scalar functions B, the reverse is simply a call to the inverse of B. However, some other functions can be used that are not normally inversible. An example:

    (10+)⍢(2↑) 3 3 ⍴ ⍳4
┌→───────┐
↓10 11 12│
│13 10 11│
│ 2  3  0│
└────────┘

The above operation represents the addition of 10 after taking the first two rows of the array. After the addition, the original removed rows are put back.

« and »: Fork

The fork is specified using « and ». It has the following form:

  • x A«B»C y is evaluated as (x A y) B (x C y)

  • A«B»C y is evaluated as (A y) B (C y)

Function chains

A sequence of two functions next to each other are executed in the same manner as a train in APL:

  • x (AB) y is evaluated as A x B y

  • (AB) y is evaluated as A B y

Because Kap uses explicit syntax for forks, this expands to any number of functions in a train. In other words:

  • x (ABCD) y is evaluated as A B C x D y

Left-bound functions

A left-bound function derives a monadic function from a dyadic function by assigning a constant to the left argument. For example, 2+ is a derived function that adds 2 to its argument. This functionality is particularly useful in trains. The following is a function that divides the argument by 2 and then adds 1: 1+2÷⍨. Example:

    A ⇐ 1+2÷⍨
    A 10
6

Math functions (namespace math)

math:sin: Sine

Monadic: Sine

Compute the sine of the argument

math:cos: Cosine

Monadic: Cosine

Compute the cosine of the argument

math:tan: Tangent

Monadic: Tangent

Compute the tangent of the argument.

math:asin: Arcsin

Monadic: Arcsin

Compute the arcsin of the argument

math:acos: Arccos

Monadic: Arccos

Compute the arccos of the argument

math:atan: Arctan

Monadic: Arctan

Compute the arctan of the argument.

math:atan2: Arctan with two arguments

Dyadic: Arctan with two arguments

Compute the arc tangent of B/A. The signs of the arguments determine the quadrant of the result value.

math:hypot: Hypotenuse

Dyadic: Hypotenuse

Calculates the square root of the sum of the squares of the aguments, ie. √(x²+y²)

math:sinh: Hyperbolic Sine

Monadic: Hyperbolic Sine

Compute the hyperbolic sine of the argument

math:cosh: Hyperbolic Cosine

Monadic: Hyperbolic Cosine

Compute the hyperbolic cosine of the argument

math:tanh: Hyperbolic Tangent

Monadic: Hyperbolic Tangent

Compute the hyperbolic tangent of the argument.

math:asinh: Hyperbolic Arcsin

Monadic: Hyperbolic Arcsin

Compute the hyperbolic arcsin of the argument

math:acosh: Hyperbolic Arccos

Monadic: Hyperbolic Arccos

Compute the hyperbolic arccos of the argument

math:atanh: Hyperbolic Arctan

Monadic: Hyperbolic Arctan

Compute the hyperbolic arctan of the argument.

math:floorc: Complex floor

Monadic: Complex floor

Computes the complex floor of the argument.

math:ceilc: Complex ceiling

Monadic: Complex ceiling

Computes the complex ceiling of the argument.

math:round: Round

Monadic: Round

Rounds the argument to the nearest integer. If the value is exactly in the midpoint between two integers, the rounding is towards the closest even number.

math:gcd: GCD

Dyadic: GCD

Compute the greatest common divisor of A and B.

math:lcm: LCM

Dyadic: LCM

Compute the least common multiple of A and B.

math:numerator: Numerator

Monadic: Numerator

Returns the numerator of a rational number. Raises an error if the argument is a floating point or complex.

math:denominator: Denominator

Monadic: Denominator

Returns the denominator of a rational number. Raises an error if the argument is a floating point or complex.

math:factor: Prime factorisation

Monadic: Factorise integers

This is a scalar function that acts on integers. This function returns an array with the same shape as the input, where each value is a 1-dimensional array of the corresponding input value’s prime factors. The list of numbers is sorted.

Passing a non-integer value to this function raises an error.

Example: Compute the prime factors of 60:

    math:factor 60
┌→──────┐
│2 2 3 5│
└───────┘

math:divisors: Calculate divisors

Monadic: Calculate divisors for an integer

This is a scalar function that acts on integers. For each value in its argument, return a list of integers that evenly divides the value.

math:re: Return real part of a complex number

This is a scalar function which, for each numeric value, returns the real part of a complex number.

    math:re 100j200 11
100.0 11

math:im: Return imaginary part of a complex number

This is a scalar function which, for each numeric value, returns the imaginary part of a complex number.

    math:im 100j200 11
200 0

math:primes: Return a list of primes up to a limit

Returns an array of all primes up to A.

math:isPrime: Check if a number is prime

This is a monadic scalar function which returns a boolean value indicating whether the value is prime.

Map functions

The functions in this section are used to create, access and update map objects. Maps are immutable, and any function that modifies the content returns a new objects with the changes applied while the original object remains unchanged.

map:with: Create a map/update a map

Monadic: Create a map

This function is called monadically with the initial content as argument. The argument can either be a single-dimensional array with an even number of elements, or a two-dimension array with 2 columns. In both cases, the key/value pairs are specified in a row-major interleaved form.

map :foo 1 :bar 5 — create a map with two elements

map 4 2 ⍴ "key0" (1 2 3 4) "key1" "Some value" "key2" (2 2 ⍴ 1 2 3 4) "key3" "Abc" — create a map with 4 elements

Dyadic: Update a map

When called dyadically, this function is used to update a map. A being is the map that will be updated, and B being a key/value definition as described in the documentation for map. This function returns the updated map.

map:appendTo: Add values to an existing element

The left argument is a map, the right argument is array of key/value pairs as per map:with. For each key, the associated value is looked up. If the value exists and is a list, the new value is appended to the existing values. If it does not exist, it is added as a single-element list.

If the value exists, but is a scalar, the new value is concatenated with the old value. However, this should probably be seen as an error and may throw an exception in later versions.

map:get: Read a value from a map

This function is called dyadically with A being the map and B being the key. The corresponding value is returned, or if the key was not found in the map.

    m ← map:with :a "test" :b "abc"
    m map:get :b
"abc"

Regular bracket indexing works on maps, and is equivalent to a call to map:get:

    m ← map:with :a 10 :b 11
    m[:a]
10

map:remove: Remove elements from a map

This function removes keys from a map. A is the map to update, and B is an array consisting of a list of keys to remove. This function returns the updated map.

map:entries: Convert a map to an array

This function is called monadically with a map as argument. It returns a two-dimensional array with two columns, where the first column is the keys and the second column the values.

    m ← map:with "foo" 10 "bar" 20 "abcde" (1 2 3)
    map:entries m
┌→──────────────┐
↓  "bar"      20│
│  "foo"      10│
│"abcde" ┌→────┐│
│        │1 2 3││
│        └─────┘│
└───────────────┘

map:size: Return the size of a map

This function is called monadically with a map as its argument. It returns the number of elements in the map.

    m ← map:with :a 11 :b 94 :c 4050 :d 91756
    map:size m
4

Flow control

: Return from a function

Monadic: Return

The function returns a value from a function. When called monadically, it returns from the innermost function. The argument is the value to be returned.

The below code will return 10, and nothing wil be printed.

∇ foo {
  → 10
  io:println "This line will never be called"
}
foo 1

Dyadic: Conditional return

When called dyadically, will return if the left argument is true. This is useful for conditional early returns.

Given the following conditional return:

if (a) {
   → b
}

This could more easily be written as such:

a → b

if: Conditional evaluation

Format: if (expression) { thenStatement }

Evaluate expression. If true, evaluate thenStatement and return the result of its last form. Otherwise, return .

Format: if (expression) { thenStatement } else { elseStatement }

Evaluate expression. If true, evaluate thenStatement and return the result of its last form. Otherwise, evaluate elseStatement and return the result of its last form.

when: Multiple clause if

The when statement is used as an alternative to series of if and else. The following sets a to be the value of some variable, or returns a message if all conditions failed.

a ← when {
  (b=1) { c }
  (b=2) { d }
  (b=3) { e }
  (1)   { "All comparisons were false" }
}

while: While loop

Format: while (expression) { body }

The while statement evaluates the body as long as expression is true.

i ← 0
while (i < 5) {
  io:println "Number: ",⍕i
  i ← i+1
}

throw: Throw exception

Exceptions are thrown using throw. Exception have a type, represented by a symbol and some associated data. The following example throws an exception of type :foo with data "test":

:foo throw "test"

When called monadically, throw will throw an exception of type :error.

catch: Catch exceptions

The catch operator is used to perform some processing when an exception is thrown. It has the following form: F catch x.

x must be either a one-dimensional array with an even number of elements, or a two-dimensional array with 2 columns. The content must be pairs of values, where each pair is a tag, followed by a function reference.

The derived function first calls F with as argument. If the invocation of F does not throw an exception, its return value is returned. If an exception was thrown, the tag is looked up in x, and if found, the corresponding function is called, with the left argument being the data that was passed to the throw call, and the right argument being the tag. The return value from the handler is then returned.

Sorting

The monadic functions and are used to sort arrays. Without an axis specifier, they sort an array based on the major axis. If given an axis argument, the value indicates which level should be used to sort.

To sort by rank 1:

    ∧ 2 2 3 ⍴ 7 5 4 9 10 8 3 6 2 11 0 1
┌┌→──────┐
│↓ 3  6 2│
││11  0 1│
│├→──────┤
│↓ 7  5 4│
││ 9 10 8│
└└───────┘

Specifying the axis argument as 1 sorts by rank 2:

    ∧[1] 2 2 3 ⍴ 7 5 4 9 10 8 3 6 2 11 0 1
┌┌→──────┐
│↓ 3  6 2│
││ 7  5 4│
│├→──────┤
│↓ 9 10 8│
││11  0 1│
└└───────┘

Regex

regex:match: Match string against regex

regex:find: Find the first regex match in a string

regex:findall: Find all matches in a string

regex:finderror: Find matches in string or raise error

regex:create: Compile regex

regex:split: Split by regex

regex:replace: Replace by regex

JSON functions

json:read: Parse JSON from file

json:readString: Parse JSON from string

json:writeString: Write Kap objects as JSON

Unicode functions

unicode:toCodepoints: Convert characters to codepoints

unicode:fromCodepoints: Convert codepoints to characters

unicode:toGraphemes: Split a string into graphemes

unicode:toLower: Convert a string to lower case

unicode:toUpper: Convert a string to upper case

unicode:toNames: Return Unicode names

unicode:enc: Encode a string to a byte array

Monadic: Encode a string as UTF-8

This function accepts a string, and returns a byte array containing the UTF-8 representation of the string.

Dyadic: Encode a string with a specific encoding

Convert the string B into an array, using the encoding specified in A. Currently the following encodings are supported:

  • :UTF8 — UTF-8

  • :UTF16 — UTF-16 with a BOM

  • :UTF16LE — UTF-16 little endian without a BOM

  • :UTF16BE — UTF-16 big engine without a BOM

  • :UTF32 — UTF-32. Currently, the endianness and BOM behaviour are different depending on platform. This will change in a later version.

unicode:dec: Decode a byte array to a string

Monadic: Decode a byte array as UTF-8

Decode the given array as UTF-8 and return the resulting string.

Dyadic: Decode a byte array with a specific encoding

Convert the byte array in B, using the encoding in A. The available encodings are as per unicode:enc.

I/O functions

io:read: Read file

Format: io:read name

Read the content of the file name and return the lines in the file as an array of strings.

io:print: Print a value

Format: io:print value

Prints value to standard output.

io:readdir: Read contents of a directory

Format: io:readdir path, format io:readdir path

When called monadically, this function assumes the left argument is an empty array.

This function loads the contents of the directory at path, and returns a 2-dimensional array of results. The first column is always the name of the directory entry, with the remaining columns decided by the format argument.

The format is a list of specifiers indicating what information should be included. Currently, the following formats are supported:

  • :size — the size of the file, or 0 if the entry is a directory

  • :type — the type of the entry, possible results are: :file, :directory or :undefined

io:readCsv: Read CSV file

This function accepts either one or two arguments. The first argument is always a string, indicating a file to be read. The second argument, if provided, is a list of keyword arguments. The following keywords are available:

  • :separator — The character used to separate fields. Default is ,.

  • :quoteChar — The character used for quoting values. Default is ".

  • :trim — A boolean value indicating if unquoted values should be trimmed. If true, whitespace before and after the value is removed. The default is 1.

  • :parseNumbers — If true, the parser will convert values that looks like numbers into numeric values, rather than strings. If a value cannot be parsed as number, the string value will be used. The default is 0.

io:writeCsv: Write a CSV file

This is a dyadic function where the left argument is a filename and the right argument is a 2-dimensional array. The content of the array will be encoded into a CSV file and written to the given file.

Experimental new I/O functions

The functions in the io2 namespace is a work in progress, and eventually they will become the new standard I/O API.

io2:open: Open a stream

The first argument is a file name that specifies which file to open. The optional second argument is a list of keywords that indicate how the file is to be opened. The following flags are accepted:

  • :input — The file is opened for input.

  • :output — The file is opened for output.

The default option is :input.

The resulting stream must be closed after being used. See close for more information.

io2:read: Read from a stream

This function reads binary data from a stream. The first argument is the stream to read from. If no second argument given, the entire content is read. If a second argument is provided, it must be an integer indicating the maximum number of bytes to read.

io2:write: Write to a stream

Write data to a stream. The first argument is a stream, and the second argument is the data to be written. If the data is a string, it’s converted to binary by encoding using UTF-8 prior to writing. For binary data, the argument must be a scalar or a single-dimensional array of integers, where each integer must be in the range 0 to 255.

io2:readLine: Read line from a stram

This function reads data up until the next newline or the end of the stream, and returns the string. If an end of file condition was seen before any data was read, the function returns null.

io2:arrayStream: Create a stream from an array

Given a byte array, return a stream which returns the data from the byte array.

HTTP functions

The http functions all returns a 3 elements list containing the following values:

  • The HTTP status code

  • The content, either as an array of characters or an array of bytes, depending on the content-type

  • The response headers, represented as a 2-dimensional array where the first column contains the header name, and the second column contains a list of all values

http:get: HTTP GET

Performs an HTTP GET request and returns the result.

http:post: HTTP POST

Performs an HTTP POST and returns the result.

http:put: HTTP PUT

Performs an HTTP PUT request and returns the result.

http:delete: HTTP DELETE

Performs an HTTP DELETE and returns the result.

Time functions

The time functions deal with time, including measurement, formatting, parsing. The time functions are located in the time namespace.

time:timeMillis: Get the current time

This function must be called monadically with the argument 0. It returns the current time in milliseconds from midnight, 1 January 1970 UTC.

time:toTimestamp: Convert integer to a timestamp object

The argument is a number that has the same form as the return value from time:timeMillis. The return value is a timestamp object.

time:fromTimestamp: Convert a timestamp object to an integer

The argument is a timestamp object, and returns an integer in the same as the return value from time:timeMillis.

time:parse: Parse an ISO 8601 string

Parse an ISO 8601 string and returns a timestamp object. Note that only UTC timestamps are supported.

time:format: Format a timestamp

Formats a timestamp object as an ISO 8601 UTC timestamp.

time:runtime: Benchmark

The special syntax function is called as follows:

time:runtime { ... }

The code inside the curly brackets will be executed, and before returning, the total runtime will be printed on the standard output. The entire call returns the last evaluated expression.

SQL

The SQL API is currently only supported with the JVM version of Kap.

sql:connect: Connect to database

Connect to an SQL database. This is a monadic function with the argument being a JDBC connection string. To connect to an SQLite database:

conn ← sql:connect "jdbc:sqlite:/path/to/database"

Note that the connection has to be closed using the close function when done. After being closed, the connection object should no longer be used. Please see close and atLeave for information how to use the close function.

sql:query: Query database

Send an SQL query to the database and return a table of the results. The left argument is an SQL connection previously obtained using sql:connect, and the left argument is a string containing an SQL statement. Example:

conn sql:query "select a,b,c from foo"

sql:update: Perform update query

Perform an SQL update operation (this includes delete, update, etc). The left argument is the connection, and the right argument is the query string. Theis function returns the number of rows affected by the operation.

sql:prepare: Prepare statement

Prepare parametrised SQL statement. The left argument is the connection, and the right is the SQL query. Any parameters are specified using a ?, which can be later provided when calling queryPrepared or updatePrepared.

A prepared statement can be closed using the close function. If not closed, it will be automatically closed when the connection is closed.

sql:queryPrepared: Perform query using prepared statement

Executes a prepared SQL query. The left argument must be a statement previously returned from prepare. The right argument must be a 1-dimensional array with a dimension equal to the number of positional parameters in the prepared statement. Each value in the argument is assigned to the corresponding position in the prepared statement and the query is executed. The result of the query is returned as per the query function.

sql:updatePrepared: Perform update query using prepared statement

Execute a prepared statement as one or more updates. If the right argument is of rank 1, it performs a single update with arguments assigned as per queryPrepared. If the right argument is a 2-dimensional array, each row represents a single update, with the columns assigned to the positional parameters in the prepared statement.

The following example inserts three rows into the table foo, which is assumed to have two columns, a and b:

conn ← close atLeave sql:connect "jdbc:sqlite:/path/to/database"
statement ← sql:prepare "insert info foo (a,b) values (?,?)
statement sql:updatePrepared 3 2 ⍴ 1 2 3 4 5 6
close statement

Graphics functions

gui:create: Create graphics window

gui:draw: Draw array

Charting functions

Linear charting functions

The linear charting functions uses the same data format. Input can be a 1- or 2-dimensional array of numbers. For 1-dimensional input, each element is a single numeric value. For 2-dimensional input, the major axis represents each dataset, with the second axis each value within that dataset.

If the argument has row or column labels, the labels are displayed in the chart.

chart:bar: Display bar chart

This function displays the dataset as a bar chart. Example:

chart:bar 2 6 ⍴ 3 5 3 7 6 1 10 12 7 10 11

This results in the following output:

bar chart

chart:line: Display line chart

This function displays a line chart. The format of the input is the same as for chart:bar.

The following example also adds labels to output:

chart:line "Row1" "Row2" "Row3" `
           labels[0] `
           "Col1" "Col2" "Col3" `
           labels[1] `
           3 3 ⍴ 1 2 2 3 3.5 2.6 5 6 3

This results in the following output:

line chart

chart:pie: Display pie chart

XY Charting functions

chart:scatter: Display scatter chart

A scatter chart is a set of X,Y coordinates along with an optional group. The input is a 2-dimensional array with either 2 or 3 columns. The first two columns are the X and Y coordinate respectively, with the third column being an identifier for the set. Each set is given a different symbol on the chart.

Example:

chart:scatter 5 3 ⍴ `
    0.3 2    "Foo" `
    1.5 1.75 "Bar" `
    2   3    "Foo" `
    1   2    "Abc" `
    0.9 0.1  "Abc" `
    3   2    "Abc"

This results in the following chart:

scatter chart

chart:plot: Function plot

The plot function is a dyadic function that accepts a two-element array as a left argument, and a function or a list of functions as the right argument. The left argument represents the left and right edge of graph, and the right argument being the functions to plot.

To plot the square root function:

0 10 chart:plot λ√

Maps

Usage

Kap supports a native map type. Objects of type map are atomic values (i.e. they behave similar to scalar numbers). A map contains a set of key/value pairs, where both the keys and values may be any Kap object.

Creating maps

To create a map, use the function map:with. When called monadically, this function accepts a list of keys and values in one of two forms: Either a 1-dimensional array containing an even number of elements. In this form, the keys and values are interleaved as such: key0 value0 key1 value1, etc. The following expression creates a map where the keys are strings and the values are lists of numbers:

a ← map:with "abc" (1 2 3 4) "def" (5 6 7 8) "ghi" (9 10 11 12)

It is also possible to specify the keys and values in a 2-dimensional array with 2 columns. The following is identical to the previous example:

a ← map:with 3 2 ⍴ "abc" (1 2 3 4) "def" (5 6 7 8) "ghi" (9 10 11 12)

Determining the size of a map

The function map:size can be used to return the number of elements in the map. I.e. calling map:size a on the array created in the example above will return the number 3.

Updating maps

Maps are immutable, in that their content cannot be changed. To modify a map, use the functions map:with and map:remove. These functions return a new map that contains the updated content.

To update a map, map:with can be called dyadically with an existing map as the left argument, and a set of key/value pairs of the same form as was used in the monadic version, and returns a map where the new keys were added to the map, and any existing keys were replaced.

map:remove accepts an existing map as the left argument, and a list of keys as the right argument. The function returns a new map where the specified keys were removed.

Appending data to an existing key

If the value associated with a given key is a 1-dimensional array, the function map:appendTo can be used to add a value to an existing list of values for a given key. If the key does not exist, it is added with the value placed in a single-element list.

    b ← map:with :foo (1 2) :bar (3 4 5 6 7)
┌Map: 2──────────┐
│:bar ┌→────────┐│
│     │3 4 5 6 7││
│     └─────────┘│
│:foo       ┌→──┐│
│           │1 2││
│           └───┘│
└────────────────┘
    b ← a map:appendTo :foo 10
┌Map: 2──────────┐
│:bar ┌→────────┐│
│     │3 4 5 6 7││
│     └─────────┘│
│:foo    ┌→─────┐│
│        │1 2 10││
│        └──────┘│
└────────────────┘
    b ← b map:appendTo :xyz 50
┌Map: 3──────────┐
│:bar ┌→────────┐│
│     │3 4 5 6 7││
│     └─────────┘│
│:foo    ┌→─────┐│
│        │1 2 10││
│        └──────┘│
│:xyz        ┌→─┐│
│            │50││
│            └──┘│
└────────────────┘

Reading data from maps

There are several different ways to access data in a map:

The array index syntax using square brackets can be used, and works in a similar way to regular array indexing:

    a["abc" "def"]
┌→──────────────────┐
│┌→──────┐ ┌→──────┐│
││1 2 3 4│ │5 6 7 8││
│└───────┘ └───────┘│
└───────────────────┘

The function map:get can also be used, where the map is specified as the left argument and the index on the right.

When using any of the above methods, attempting to look up a nonexistent element will return null.

It is also possible to use period dereferencing. When using this method, only a single value may be looked up, and if the key is missing, an error will be thrown.

    a.("ghi")
┌→─────────┐
│9 10 11 12│
└──────────┘

It is also possible to return the entire content of a map in the form of a 2-dimensional array using the function map:entries. The form of the data is similar to that used when creating a map:

    map:entries a
┌→─────────────────┐
↓"def"    ┌→──────┐│
│         │5 6 7 8││
│         └───────┘│
│"abc"    ┌→──────┐│
│         │1 2 3 4││
│         └───────┘│
│"ghi" ┌→─────────┐│
│      │9 10 11 12││
│      └──────────┘│
└──────────────────┘

As array content is unordered, the order of the key/value pairs in this data will usually be different from what was used when creating the map.

Retrieving the keys from a map

All keys in a map can be obtained using the function map:keys. This function returns a 1-dimensional array of all keys in the map.

Design considerations

The following section describes the decisions leading to the current design of maps in Kap.

Different array programming languages have taken different approaches to implementing maps (also called hashtables or dictionaries). Many languages have adapted existing array manipulation functions to maps, so that the user may treat maps as a variation of a 2-dimensional array. With such support, one would be able to do things like 1↑someMap to retrieve a single key/value pair, for example. For example, TinyAPL decided to take this approach.

In Kap, it was decided to make the map a scalar object. The reason for this is that while maps do share a lot of common properties with arrays, they are also different in several fundamental ways. Specifically, maps are highly inappropriate for anything which is not their primary use: To look up values by key. While it certainly would be possible to allow the existing array manipulation functions to operate on maps, and there may in fact be some useful usecases, for the most part the behaviour would be both surprising (because maps have no ordering) and inefficient. If this kind of manipulation of data in maps is needed, the function map:entries can be used to convert it to an array first, and then regular array functions can be used to manipulate the content.

Definitions

Atom

Atoms are values with rank-0, and which are not enclosed arrays. Atoms cannot be enclosed () or disclosed () . Instead, performing these operations on an atomic value always returns the value itself.

Axis specifier

An axis specifier is integer value that specifies which axis of a multidimensional array to act on. Axes are numbered from 0 to the dimensionality of the array - 1. For example, in a 2-dimensional array, axis 0 refers to the rows, while axis 1 refers to the columns.

List

An instance of an n-tuple. Lists are created using the function , or specified as a series of elements separated by ;. For more information, see the section N-tuples.


1. Some text in this section originates from APLWiki