iogiiDocsSourceQuick RefOnline Interpreter
DocsIO ⸱ Syntax ⸱ TypesVectorizationCircular ProgrammingOpsExamplesWhy

Syntax

Comments

# is a comment, but only if followed by a space. My editor makes it easy to comment / uncomment lines of iogii if I just tell it to use ruby syntax for .iog files.

Literals

Integers are any continuous sequence of digits. Leading 0's are a separate number.

0050 → 0 0 50
↗️

Chars are a ` followed by a single character. \ can escape \, n (newline), 0 (null character), x00 for any two digit hexadecimal.

'\x0a → '\n'
↗️

Strings are enclosed in "", the last " can be omitted if it is the last thing in your program. \ can also be used to escape ".

Identifiers ([A-Za-z][A-Za-z0-9]*) will be broken into individual characters if there is no op or variable by that name.

> matching

End brackets (>) match with loop ops (i iterate, e expand, f foldr, and m meld) like parenthesis. Think of iefm as left brackets that all match with > as the right bracket.

And as a reminder from the overview If end brackets are missing, they are implicitly inserted at the first valid location. i e f m can use values from left, they are normal syntactic elements.

The value before > is passed to the matching i e f m op. The result of the op is returned after the >.

It would be rare to need nested loops that require two >s. But understanding the matching algorithm could be useful in such a case:

When developing code with nested loops, I recommend explicitly using > until you are ready to optimize, then [try to] make them implicit.

Note that folds would always be invalid if there were only unary ops applied the arg, so they will not implicitly close until there has been a binary op (or trinary). It is still possible to right completely jibberish folds, but detecting them would require looking at type level information, while bracket matching is done before purely before this.

0 foldr succ 1,2,3 + → 9
↗️

The fold does not terminate after succ, but an iterate would.

0 iterate succ 1,2,3 + → [1,3,5]
↗️

>,

You can proceed > with any number of ,s. These end brackets skip matching as many i e f ms as there are ,s. This could be useful to create loops that are functions of each other in a complicated manner.

This is useful if you wish to to use an outer loop's var inside and inner loop. I used it for the rule 110 problem and would provide the code but don't want to spoil that problem).

Unmatched End Brackets

If an end bracket cannot be matched, then it will act like a unary op that sets the implicit value with its arg (see below to learn more about the implicit value).

5> ++ → 15
↗️

Input Placement

As mentioned in IO input placement can always be done implicitly by rotating your program so that the input would come first (then omit it). If you are using input multiple times, you have choices about which one you can make implicit.

Implicit Values

If an op uses more args than there are items on the stack, it creates implicit args as needed (that is an actual op name you can use to simulate the effect as needed too).

If you have not set the implicit value using unmatched > then the implicit value is the value yielded by the innermost loop function you are in. (Which for the main program it is the input).

In this example the implicit value is used in the main program so it is equivalent the input again:

4
*
16
↗️

In this example, iterate consumes the input as its starting value, then the function multiplies the loop variable by itself (since the implicit value is used which is that same loop variable).

4
iterate * >
4 16 256...
↗️

If the input is empty and used as auto input, then it is removed and only implicit values are placed.

4 iterate * >
4 16 256...
↗️

If you are using input and implicit values, implicits are created as needed after your program is unrotated. So for example if this was your program and it used two more args than existed:

[main program] [extra values]

It would mean:

implicit implict [extra values] input [main program]

$

$ is the value of the innermost loop function it is in. (Which is input if present, implicit value otherwise).

4 iterate $ * >
4 16 256...
↗️

Use in main program:

4
$$*
16
↗️

Here the implicit value is set to 4 and no input is present:

4> del $$*
16
↗️

Other ways to use values multiple times

Postfix is perfect at representing expression trees, but what about when you need to use a value more than once (which would technically be a directly acyclic graph (DAG) not a tree)?

If that value is the loop value, you can just use $.

Or if it just so happens to be used at the left hand side of the tree you could set the implicit value and use it implicitly.

If it is used twice and only simple manipulation is done before combining the two uses, you can use one of dup, mdup, peek, or mpeek. These correspond to the 4 cases the S combinator (Sxyz = xz(yz)), for each of x or y being the identity function.

They can't be used to handle all cases because they don't take in arbitrarily complex functions as args (doing so would require > which would then not be shorter than iogii's other method, see below).

mdup ; and mpeek { ops take a function, but this function does not match with >'s so it can only handle simple cases. > would not be useful anyway since this would be the same number of characters as using set next var (see below). And this reduces the chances of a loop function needing and extra > because it got matched with one of these.

set

set is assignment, the token following the set has the value before the set assigned to it. This overrides any other meaning of that token for the entire program (both before and after the set).

1 2+ set foo foo → 3 3
↗️

let is a set followed by a del.

These have long names because they are intended only for debugging since there is a shorter way to set vars...

Set Next Var =

= saves the top of the stack to the next available var. The next available var is a capital letter A-Z chosen in a special way so that you never overwrite an op that you want to use. How can it do that?! Find the largest gap between used letters and choose the next one. Technically it is the largest difference between starting runs of used letters (so that adding the use of the next var does not change the selection process).

So if you don't use any capital letter ops then the first use of = will save to A, and the next to B.

5= A + → 10
↗️

These values can be used before they are set since iogii is really just a bunch of timeless static definitions.

A 5= + → 10
↗️

If you use capital letter ops A, C and W now the largest gap is between C and W so the first use of = will save to D.

If you use so many = that you fill the largest gap completely it will not work, so there is a limit to how many times you can use this.

Note that you MUST use the saved value (otherwise it will think that an op you used is actually a variable being used).

Sometimes it can be tedious to find the largest gap yourself, you could use iogii to automatically find it by using a bunch of =s - more than there are consecutive capital letters (which will cause an error saying which var is unused).

CWA === → ERROR: 1:6 (=) Sets register 'D' but it is never used
↗️

Set Next Vars are powerful but I recommend using set as you develop your program and only switching to them at the end, since it would be tedious if you frequently change which capital letter ops you use in your code.