Skip to content

Operators

op gives a function a symbolic spelling. Operators such as + and :: come from declarations or explicit imports. This guide assumes familiarity with functions and modules.

Define and use an operator

With a host-provided Int and add, define a binary operator like this:

fn add_int(a: Int, b: Int) -> Int { add(a, b) }

op _ + _ { impl add_int }

fn three() -> Int { 1 + 2 }

Each _ is an operand slot: 1 + 2 calls add_int(1, 2). Slots supply the function's arguments in written order. The body contains one impl target: a function name, an imported path such as math.add, or a newtype member such as List.cons. Put any argument reordering or other adaptation in a named helper; calls and inline lambdas cannot be impl targets.

Declare local targets before the operator, and the operator before functions that use its syntax. Import a target from another module through a selective import or an explicit module alias; a slash-qualified path is not an impl target.

Choose how it chains

SlotAccepts
_One operand, such as a name, literal, call, or parenthesized expression
__An operand or a chain of this same operator
___An operand or a chain of any one operator

The position of __ or ___ chooses the grouping:

PatternUseEquivalent calls
_ + _(a + b) + cadd(add(a, b), c); parentheses required
_ + __a + b + cadd(a, add(b, c))
__ + _a + b + cadd(add(a, b), c)
_ $ ___f $ a + bapply(f, add(a, b))
- __- - aneg(neg(a))
__ ?a ? ?check(check(a))

A pattern may contain at most one __ or ___; adjacent slots and longer underscore runs are rejected. Kio has no operator precedence: write a + (b * c) or (a + b) * c. A greedy slot admits one operator's chain, but still needs parentheses when that chain mixes operators. Prefix unary operators bind to their operand, so - a + b means add(neg(a), b).

Multi-token patterns

A pattern can contain several symbols and operands:

fn cond[A](c: Bool, t: A, e: A) -> A {
  if! c {
    t
  } else {
    e
  }
}

op _ ? _ : __ { impl cond }

fn choose(c: Bool, d: Bool) -> Int { c ? 1 : d ? 2 : 3 }

choose calls cond(c, 1, cond(d, 2, 3)).

For a delimited pattern, op _ ( <| _ |> ) { impl index } permits xs <| a + b |>: the pattern's parentheses let the enclosed slot accept a single-operator chain. They are omitted at use sites. Such groups cannot nest or contain ___. A recursive slot can also precede closing symbols: _ <| __ |> permits a <| b <| c |> |>.

Allowed symbols

Fixed operator tokens use these ASCII characters:

+ - * / % ^ ~ ? @ # $ \ ' ` < > = ! & | : .

Combine them into tokens such as +, !=, <=, ::, or <|>. Whitespace separates tokens: && ++ and &&++ are different spellings.

  • = must be quoted in declarations and imports: op _ (=) _ { impl equal }. Use it without quotation: a = b. Both : and -> work directly.
  • A token starting with . must contain at least two dots: .. and .+. work; ., .>, and .+ are reserved, even when quoted.
  • A token may contain at most one /; // starts a comment.
  • Letters, digits, Unicode symbols, and square brackets are not fixed operator tokens. Square-bracket delimiters use varop.

Export and import

Use pub op to export an operator and make its directly named target public too. For example, pub op _ + __ { impl add_int } requires pub fn add_int. For pub(path), the target must be visible throughout that path. A newtype member target requires both its type or identity alias and the member to meet the same visibility requirement.

Import the complete pattern, including its slot kinds, quotation, and grouping: import math(op _ + __);. For example, the dictionary library exports => as a pair-building operator:

module entry_example;

import dict(op _ => _);

host type Int role(i32);

fn entry() -> Int & Int { 1 => 10 }

Importing the operator is sufficient to use its syntax; importing only its function is not. Write each operator import once. Conflicting patterns in one scope are rejected; in particular, slot changes do not let two operators reuse the same opening pattern. Prefix and non-prefix operators can share symbols, as with unary and binary -.

The variadic-operator guide covers collection literals. The optics case study shows a larger operator vocabulary. See the operator specification for the complete grouping and conflict rules.