Docs

How i++ works, from one combinator to complex numbers.

The i combinator

i++ has a single primitive: i. It is the universal iota combinator, defined by one reduction rule:

i x = x S K

From that single rule you get the familiar SKI basis. The prelude defines:

I = i i
K = i (i I)
S = i K

Once you have S and K, you can build B, C, T, and effectively any other combinator.

Application and grouping

Application is just juxtaposition: writing two terms next to each other applies the left to the right. Parentheses group sub-expressions.

f x y       # means ((f x) y)
S (K K) I
i (i I)

Definitions and modules

A definition binds a name to a term in the current session:

export ID = i i

ID x
# => x

Use export to make a name visible to modules that import this one. Use import Module to load a module.

import Combinators
import Math

Numbers

Numeric literals are complex numbers. Real integers, decimals, and imaginary values with j are all supported.

42
-3.14
2.5+4j
-7j

The EML operator

When a number is applied to another number, i++ uses the EML binary operator:

a b = exp(a) - ln(b)

That single operator is enough to recover exponentials, logarithms, and elementary arithmetic. The trick is choosing the right arguments:

  • x 1 = exp(x), because ln(1) = 0. The prelude defines EXP = T 1 — it applies its argument to 1.
  • 1 x = e - ln(x). Wrap it again and the offset cancels: 1 ((1 x) 1) = ln(x). That is why the prelude defines LN = B (B 1 EXP) 1.
  • Subtraction falls out directly: (LN x) (EXP y) = x - y.

The underlying idea comes from EML — All elementary functions from a single binary operator.

Examples

import Combinators
import Math

EXP 1            # e
LN E             # 1
(LN 5) (EXP 3)   # 2
S K K x          # x