Operators
Operators as functions
Operators are ordinary functions with special names. They can be used infix, prefix, postfix, or passed around like any other function.
Defining operators
You define operators by naming a function with a valid operator name, encased in backticks:
def `+++`: string, string -> string = { a, b -> a + b }
def r = "one" +++ "two"
Operators can take more than two arguments. Extra arguments are passed as a record, in the same way as piping:
def `<+>` = { a, b, c -> ... }
def r = a <+> (b, c)
Using operators as functions
Since operators are just specially-named functions, you can also use them in a non-operator way:
def r1 = "one" +++ "two"
def r2 = `+++`("one", "two")
def f = `+++`
Also, lambda syntax supports an operator-based shorthand for using operators:
[1, 2, 3] \fold(0) { + }
Arithmetic and comparison
Core arithmetic (+, -, *, /, %, **) and comparison (==, !=, <, <=, >, >=) on the built-in types are attached definitions: 1 + 2 resolves to int.`+`, exactly as any other attached function is resolved by the type of its first argument (here, the left operand). To give your own type an operator, attach a definition to it:
def Vector.`+` = { a, b -> Vector(x = a.x + b.x, y = a.y + b.y) }
def c = a + b -- resolves to Vector.`+` because `a` is a Vector
Generic code that needs an operator on an unknown type declares a context requirement instead, such as [Sum(a)] or [Num(a)], and the compiler synthesises the instance from the type’s attached definitions (see Contexts). Loading a context with use only overrides the instance that such generic code sees for that particular type; it never changes what 1 + 2 means.
Pipe and composition
Piping uses \, and composition uses >> and <<:
def normalize = trim >> toLowerCase
def result = data
\filter { .isActive }
\map { .name }
\sort
Valid operator names
An operator name is any sequence of one or more of the following characters: +, -, *, /, %, ^, ~, <, >, =, !. For example, ++, >>> and <+> are valid operator names, but +a is not.
The characters |, &, ?, #, @, $, : and \ are not operator characters; they are syntax (see below).
Boolean operations are the keywords and, or and not, not operators.
Reserved spellings
Some sequences built from operator characters are syntax, not operators, and cannot be defined or redefined:
| Token | Meaning |
|---|---|
--, --- | Line and block comments |
-> | Lambda, match arm, function type |
= | Definition, named field, pattern test in if |
\ | Pipe |
.. | Range |
... | Spread and rest |
:= | Assignment |
=> | Map entry |
| | Match arm, or-pattern, union type |
& | And-pattern, intersection type, context combination |
# | Tag prefix |
@ | Attribute prefix |
$ | Nominal prefix |
: | Type annotation |
? | Optional marker |
??? | Unimplemented placeholder |
The following operators are defined by the standard library as attached definitions on the built-in types. You can attach them to your own types, but you cannot redefine them globally:
| Operators | Meaning |
|---|---|
+, -, *, /, %, ** | Arithmetic |
==, !=, <, <=, >, >= | Comparison |
>>, << | Composition |
++ | Concatenation |