That's the whole language. For comparison, the lambda calculus
requires an infinite stock of distinct variable symbols, and even
Combinatory Logic requires at least three symbols, including S, K, and
something to serve the function of parentheses.

The syntax generates strings like i, *ii,
*i*ii, or **ii*ii, but not ii,
i*i, or **ii.

The semantics is expressed using the lambda calculus. The symbol
"^" stands for lambda, and the functions S and K are the standard
functions from Combinatory Logic (henceforth referred to as "CL"): S =
^xyz.xz(yz) and K = ^xy.x. If you're not
familiar with CL, see, e.g., Hankin's 1994 Oxford book, Lambda
Calculi: A guide for computer scientists, or the wonderful
Unlambda page for a thorough explanation. Note that as usual,
functional application is left-associative, so that, e.g.,
xSK = ((x(S))(K)). The expression
[F] indicates "the meaning of the expression F"; in other
words, the star prefix in the syntax corresponds to functional
application in the semantics.

Iota is highly similar to other simple Turing-complete languages.
For one thing, the trick of using the star prefix instead of left and
right parentheses is a strategy also adopted in Unlambda. (In fact,
in general, exploring the
Unlambda page will help tremendously in understanding this
document.) For another, Hankin (page 61) proposes the term
^x.xKSK as a one-element basis for the lambda-calculus;
my language pursues essentially the same idea, except that my unique
basis element is marginally simpler (^x.xSK instead of
^x.xKSK). Of course, when there is only one element in
the basis, even a marginal difference in simplicity is a substantial
fraction of the whole!

18 March 2002: Jeroen Fokker compares a number of one-combinator
bases. He claims that his (^f.fS(^x^y^z.x)) is the smallest, but does
not consider my combinator. For purposes of comparison, my combinator
can be rendered as ^f.fS(^x^y.x), which is clearly smaller. Fokker is
trying to minimize the number of combinators it takes to reconsruct K
and S, and on that score, he wins (2 and 3, respectively, for him
versus 4 and 5 for me--see below). But in terms of the size of the
combinator itself, I win. See
Fokker 1992, `The systematic
construction of a one-combinator basis for Lambda-terms', Formal
Aspects of Computing4:776-780, available
here
.

When executed in a Scheme interpreter, this program will read one
well-formed Iota expression, then return the function denoted by the
Iota expression. (Scheme exercise: what happens when the input does
not contain a well-formed Iota expression? Consider, for instance,
trying as input just "*".) If you want to try out Iota,
you can either download the reference interpreter and run it in a
Scheme interpreter, or try the JavaScript program below.

Since the expression "*[A][B]" in Iota means the same thing as
"AB" in CL (namely, functional application in which the meaning of A
is applied as a function to the meaning of B), we need only establish
the appropriateness of the translations of the lexical items I, K, and
S. Bear in mind that functional application is left-associative:

This establishes that for every expression in CL, there is an
expression in Iota with the same meaning.

In addition, it is easy to find a meaning-preserving mapping from
Iota into CL: the semantics in the definition for Iota are given as a
mapping from Iota to the lambda calculus, and there are well-known
techniques for mapping the lambda calculus into CL (see, e.g., Hankin
or the Unlambda page for details).

The semantics of Jot are similar to those of Iota, but not
identical. For one thing, the 1 operator does not treat
0 as a unit, but is capable of dividing the meaning of 0
into its K half and its S half. As a result, there are typically more
1's than 0's in a useful Jot program, in comparison with
Iota, in which there must always be exactly one more i than
there are *'s in order for the expression to be well-formed.

Here are the rules for mapping an arbitrary CL program into Jot:

CL Jot
K ==> 11100
S ==> 11111000
AB ==> 1[A][B]

Note that every CL expression translates into a Jot expression that
begins with 1.

Constructing a Goedel-numbering now becomes trivial: simply express
each natural number in base 2 as a string of 1's and
0's. Since every such string is a legitimate Jot program, each
base-2 numeral will give rise to a legitimate Jot program.
Furthermore, since the base 2 representation of a number always begins
with a 1, and since the translation of each CL expression
begins with a 1, for every CL program there will be a numeral
with the same interpretation. Since CL is Turing-complete, we have
a suitable Goedel-numbering in which the base-2 representation of the
number itself is treated as a program directly.

This program also denotes an infinite loop, but with a
difference: the equivalent lambda expression reduces to an expression
that is longer than the original. (Translation of
S(SK)(SK)(SII) in CL, and of
```s`sk`sk``sii in Unlambda; similar in behavior to
the lambda expression
(^x.xx)(^x.x(xx)).) On my Scheme interpreter, the behavior is
different than the last example; rather than looping endlessly, it
causes a stack overflow. On the JavaScript interpreter, however, it
causes "too much recursion", just like the first example.

You can verify for yourself that just about any other well-formed
Iota program returns almost instantly without producing a JavaScript
error ("just about", because you might manage to find another infinite
loop!): just type an Iota program into the input window, and click
"Run Iota".