Esc
Start typing to search...

Operators

Keel provides a rich set of operators for arithmetic, comparison, logical operations, and more.

Arithmetic Operators

Basic mathematical operations:

OperatorDescriptionExample
+Addition1 + 2
-Subtraction5 - 3
*Multiplication4 * 2
/Division10 / 3
//Integer division10 // 3
%Modulo10 % 3
^Power2 ^ 8
let addition = 5 + 3

let subtraction = 10 - 4

let multiply = 6 * 7

let divide = 15 / 3

let intDiv = 10 // 3

let modulo = 17 % 5

let power = 2 ^ 10

let negative = -42  -- -42 (negation)

power
Try it

Integer vs Float Division

Division behavior:

let floatDiv = 10 / 3

let intDiv = 10 // 3

(floatDiv, intDiv)
Try it

Numeric Type Promotion

When mixing Int and Float, Int is promoted to Float:

let x = 1 + 2.5

let y = 3 * 1.5

x + y
Try it

Comparison Operators

Compare values and return Bool:

OperatorDescriptionExample
==Equala == b
!=Not equala != b
<Less thana < b
<=Less than or equala <= b
>Greater thana > b
>=Greater than or equala >= b
let eq = 5 == 5

let neq = 5 != 6

let lt = 3 < 5

let gt = 5 > 3

let lte = 3 <= 3

let gte = 5 >= 4

(eq, neq, lt, gt, lte, gte)
Try it

== and != work on all scalar types (Int, Float, Decimal, Bool, String, Char, Symbol, Unit), Enum variants, and structural collections (Tuple, List, Record). They do not work on functions, DataFrames, Matrices, or open record types.

Logical Operators

Boolean logic operations:

OperatorDescriptionExample
&&Logical ANDa && b
||Logical ORa || b
notLogical NOTnot a
-- And (both must be True)
let and1 = True && True

let and2 = True && False

-- Or (at least one must be True)
let or1 = True || False

let or2 = False || False

-- Not (negation)
let not1 = not True  -- False

let not2 = not False  -- True

let not3 = not (1 > 2)

-- True
let not4 = not not True  -- True (double negation)

(and1, or1, not1, not3)
Try it

Short-circuit Evaluation

Logical operators use short-circuit evaluation:

-- False && ... returns False immediately without evaluating the right side
let result = False && True

result  -- False
Try it

String Operators

String manipulation:

"Hello, " ++ "World!"
Try it

List Operators

Working with lists:

OperatorDescriptionExample
::Cons (prepend)1 :: [2, 3]
++Concatenation[1, 2] ++ [3, 4]
-- Cons (prepend element)
let consed1 = 1 :: [2, 3]

let consed2 : [Int] = 1 :: (2 :: [])

-- Concatenation
let joined = [1, 2] ++ [3, 4]

joined
Try it

Pipe Operators

Chain function calls elegantly:

OperatorDescriptionExample
|>Pipe forwardx |> f
<|Pipe backwardf <| x
fn double : Int -> Int
fn double x =
    x * 2

fn addOne : Int -> Int
fn addOne x =
    x + 1

-- Forward pipe
5 |> double  -- Same as: double 5 = 10
Try it
import List

-- Pipeline example
[1, 2, 3, 4, 5]
    |> List.filter (|x| x > 2)
    |> List.map (|x| x * 2)

-- [6, 8, 10]
Try it

Function Composition

Compose functions into new functions:

OperatorDescriptionExample
>>Compose (left to right)f >> g
<<Compose (right to left)g << f
-- Forward composition (f first, then g)
let addOne = |x : Int| x + 1

let double = |x : Int| x * 2

let addThenDouble = addOne >> double

addThenDouble 5  -- 12 (5 + 1 = 6, 6 * 2 = 12)
Try it
-- Backward composition (g first, then f)
let addOne = |x : Int| x + 1

let double = |x : Int| x * 2

let doubleThenAdd = addOne << double

doubleThenAdd 5  -- 11 (5 * 2 = 10, 10 + 1 = 11)
Try it

Result Propagation Operator

The ? postfix operator works on Result values:

OperatorDescription
?Unwrap Ok value; short-circuit with Err if the result is an error
-- ? unwraps Ok values and short-circuits on Err
let addOne = |x: Int| Ok (x + 1)
let result = 5 |> addOne
result?
Try it

If the expression is Ok v, ? evaluates to v. If it is Err e, the expression evaluates to Err e (the error is preserved). Applying ? to a non-Result type is a compile error.

Operators with DataFrame Expressions

Arithmetic (+, -, *, /, %, ^), comparison (==, !=, <, <=, >, >=), boolean (&&, ||), and unary (-, not) operators work directly on Expr values from the DataFrame.Expr module. When either operand is an Expr, scalars are automatically coerced to literal expressions:

-- Operators work directly on column references
import DataFrame
import Result

import DataFrame.Expr as Expr

let df =
    DataFrame.fromRecords
        [ { price = 10.0, quantity = 2, active = True }
        , { price = 20.0, quantity = 3, active = False }
        ]

-- Arithmetic: @col * scalar -> Expr
-- Comparison: @col >= scalar -> Expr (boolean)
-- Boolean: Expr && Expr -> Expr
let expr = @price * 1.1

df
    |> DataFrame.applyExprs [(@adjusted, expr)]
    |> Result.andThen (DataFrame.column @adjusted)
    |> Result.withDefault []
Try it

See the DataFrame Expressions guide for full details.

Best Practices

  1. Use parentheses when precedence is unclear
  2. Prefer pipes (|>) for data transformation chains
  3. Use composition (>>) to build reusable function pipelines
  4. Use != for inequality (not /=)

Next Steps

Learn about functions to create reusable code.