User:Gilbert189/Iternary
- This article is just a draft. See User:Gilbert189#Drafts for more info.
Iternary is a concatenative esolang that uses iterators as their main datatype.
Iterators
Iterators are a sequence of integers. They can be created by three ways:
Numbers
A number in the source code corresponds to an iterator of that number, repeating infinitely. This form of iterator is called a constant iterator (or simply a constant).
> 65 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
iota
and jot
The niladic iota
function generates an iterator of an ascending sequence, starting at 0.
> /number /space-seperated /limit 10 > iota 0 1 2 3 4 5 6 7 8 9
The monadic jot
is like iota
, however the iterator only has a specified length, which is the first value of the input iterator.
> 5 jot 0 1 2 3 4
Sequence builder
You can also generate an iterator by a sequence builder. They are written in [brackets]
.
It consists of two parts:
[0 1 ... $2 $1 +] === ======= | |_____ Equation for next term |_______________ Initial terms
A number prefixed with $
signifies the last n-th number of the iterator, starting with 1.
When evaluated, they represent a constant iterator of that number.
The number used is the first value on the resulting iterators, ordered from the most recently pushed iterator.
For example, the above sequence builder generates the Fibonacci sequence:
> [0 1 ... $2 $1 +] 0 1 1 2 3 5 8 13 21 34
$
by itself is a monadic function that returns a constant iterator of the last n-th number of the iterator,
with n being the first value of the input iterator.
If $
ever tries to index an out-of-bounds number, the iterator stops.
For example, this sequence builder generates the Hofstadter's Q sequence.
> [1 1 ... $2 $ $1 $ +] 1 1 2 3 3 4 5 5 6 6
Sequence builders may omit the equation for the next term, resulting in a finite iterator that only contains the initial terms.
> [1 3 5 7 9] 1 3 5 7 9
Functions
Functions are represented by words like acc
.
They perform a specific operation to popped values in the data stack and pushes any number of iterators back.
Usually, the output iterators stops when any input iterators have been exhausted.
Notice how the output of +
is finite, despite the infinite-size iota
.
> [7 4 5 9] iota + 7 5 7 12
Standard functions
Here is a list of functions in Iternary:
(Signatures here represents what iterators that's returned: x -- y
pops out x
as input, and pushes y
as output, while a b -- a
pops a
and b
in that order, and pushes the modified a
.)
Name | Signature ( I -- O )
|
Description | Notes |
---|---|---|---|
iota I
|
-- y
|
Creates an iterator of an ascending sequence, starting at 0.
> iota 0 1 2 3 4 5 6 7 8 9 |
|
jot J
|
x -- y
|
Creates an iterator of an ascending sequence, starting at 0, and ends in the first value of x - 1.
> 5 jot 0 1 2 3 4 |
|
acc ++
|
x -- y
|
Creates an iterator that is the running sums of x .
> iota acc 0 1 3 6 10 15 21 28 36 45 |
The initial value is 0, so the first value of y equals the first value of x .
|
mult-acc **
|
x -- y
|
Creates an iterator that is the running products of x .
> iota pop mult-acc 1 2 6 24 120 720 5040 40320 362880 3628800 |
The initial value is 1, so the first value of y equals the first value of x .
|
reverse !
|
x -- y
|
Creates an iterator that contains the values of x , in reverse order
> 5 jot reverse 4 3 2 1 0 |
Not suitable for infinite iterators. |
repeat @
|
x -- y
|
Creates an iterator that contains the values of x , repeated infinitely.
> [1 2 3 4] repeat 1 2 3 4 1 2 3 4 1 2 |
Not suitable for infinite iterators. |
concat ..
|
a b -- y
|
Creates an iterator that contains the values of a and b , concatenated in that order.
> 5 jot 3 jot reverse concat 0 1 2 3 4 2 1 0 |
|
crop |--|
|
x y -- x'
|
Selects values of x from where the values of y turns positive, to where the values of y turns non-positive.
> iota copy [0 0 1 1 1 1 1 0 ... 0] select 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
0 and the end of iterator are non-positive.
If no positive numbers are found, the iterator is a blank iterator. (equivalent to |
select ?
|
x0 x1 y -- x'
|
Creates an iterator that contains either the value of x0 or x1 depending on the value of y .
> iota 0 - iota iota 2 % select 0 1 -2 3 -4 5 -6 7 -8 9 |
Invalid values of y ends the iterator.
A positive number prefix may be added to specify the amount of iterators to select. > iota iota 0 - iota 2 * iota 3 % 3select 0 -1 4 3 -4 10 6 -7 14 9 |
mux #
|
x0 x1 -- x'
|
Creates an iterator which contains values of x0 and x1 as selected by y
> iota iota 0 - iota 2 % mux 0 0 1 -1 2 -2 3 -3 4 -4 |
Invalid values of y ends the iterator.
A positive number prefix may be added to specify the amount of iterators to mux. > iota iota 0 - iota 2 * iota 3 % 3mux 0 0 0 1 -1 2 2 -2 4 3 |
demux #?
|
x y -- x0 x1
|
Creates iterators that contains the value of x , with the assigned iterator set by the value of y .
> iota iota 2 % demux 0 2 4 6 8 10 12 14 16 18 1 3 5 7 9 11 13 15 17 19 |
Each iterator gets its own queue to store its values. When an iterator is advanced when the queue is empty, x is advanced in respect to y until its iterator queue gets a value enqueued. Invalid values of y ends the iterator.
Since the values has to be stored on memory, using this operator is not recommended if one iterator severely lags from another. A positive number prefix may be added to specify the amount of iterators to demux. > iota iota 3 % 3demux 0 3 6 9 12 15 18 21 24 27 1 4 7 10 13 16 19 22 25 28 2 5 8 11 14 17 20 23 26 29 |
next ;
|
x -- x
|
Advances x and returns it back.
> iota next 1 2 3 4 5 6 7 8 9 10 |
|
first <|
|
x -- y
|
Creates an iterator which is a constant iterator of the first value of x .
> iota first 0 0 0 0 0 0 0 0 0 0 |
|
last |>
|
x -- y
|
Creates an iterator which is a constant iterator of the last value of x .
> 5 jot last 4 4 4 4 4 4 4 4 4 4 |
Not suitable for infinite iterators. |
expand \
|
a b -- y
|
Creates an iterator which contains a_1 repeated b_1 times, then a_2 repeated b_2 times...
> [4 0 9 6] iota expand 0 9 9 6 6 6 |
|
copy :
|
x -- y x
|
Creates an iterator which is a copy of x . When x is advanced, y is also advanced as well.
> iota copy next 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 > "Notice that one starts with 11" > "(the act of printing it also advances the iterator)" |
A positive number prefix may be added to specify the amount of copies returned.
> iota 2copy next 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
fork =
|
x -- y1 y2
|
Creates two iterators which contains the values of x . Unlike copy , advancing one iterator doesn't advance the other.
> iota fork next "Notice that one still starts at 0" 1 2 3 4 5 6 7 8 9 10 0 1 2 3 4 5 6 7 8 9 |
When one iterator has been advanced, the value is stored on a queue of values, where other iterators could refer to if they're lagging behind. When all the iterators have been advanced beyond that value, the value is dequeued to save memory.
Since the values has to be stored on memory, using this function is not recommended if one iterator severely lags from another. A positive number prefix may be added to specify the amount of copies returned. > iota 2fork next 1 2 3 4 5 6 7 8 9 10 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 |
rotate @@
|
x y -- y x
|
Rotates the two topmost value of the stack.
> iota fork next rotate 0 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 10 |
A number prefix may be added to specify the rotation size. Positive values rotates from top to bottom, and vice versa.
0 does nothing, while -1 and 1 rotates the entire stack. > iota 2fork next 3rotate 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 10 > iota 2fork next -3rotate 0 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 10 0 1 2 3 4 5 6 7 8 9 |
pop ~
|
x --
|
Pops an iterator out of the data stack.
> iota pop > |
|
consume ~~
|
x --
|
Consumes the topmost iterator of the data stack.
> 50 jot copy consume > "See how the copy has been consumed as well?" |
|
add +
|
a b -- y
|
Creates an iterator with values of a and b added together.
> [2 5 3 1] [-3 2 -6 4] + -1 7 -3 5 |
|
subtr -
|
a b -- y
|
Creates an iterator with values of a and b subtracted together.
> [2 5 3 1] [-3 2 -6 4] - 5 3 9 -3 |
The most recently pushed iterator gets put in the right side. (the subtrahend) |
mult *
|
a b -- y
|
Creates an iterator with values of a and b multiplied together.
> [2 5 3 1] [-3 2 -6 4] - -6 10 18 4 |
|
div /
|
a b -- y
|
Creates an iterator with values of a and b divided together. (floor division)
> [2 5 3 1] [-3 2 -6 4] - 0 2 0 0 |
The most recently pushed iterator gets put in the right side. (the divisor).
Division by zero ends the iterator. |
mod %
|
a b -- y
|
Creates an iterator with the division remainders of values of a and b .
> [2 5 3 1] [-3 2 -6 4] - -1 1 -3 1 |
The most recently pushed iterator gets put in the right side. (the divisor). Only negative divisors result in a negative result.
Division by zero ends the iterator. |
exp ^
|
a b -- y
|
Creates an iterator with the values of a to the power of values of b .
> [-3 2 -6 4] [2 5 3 1] ^ 9 32 -216 4 |
Encountering undefined values like 00 and 0-1 ends the iterator. |
sign +/-
|
x -- y
|
Creates an iterator containing the sign of x .
> 5 jot 2 - sign -1 -1 0 1 1 |
|
print
|
x --
|
Prints the input iterator under the specified format. Could be useful for UIs.
> 5 jot print 0 1 2 3 4 |
Stops upon reaching an out-of-range number. |
input
|
-- x
|
Prints the input iterator under the specified format. Could be useful for UIs.
> input 0 1 2 3 4 0 1 2 3 4 |
Stops upon reading an invalid input. |
Auxiliary functions
These functions may be implemented (or toggled with the /enable-
and /disable-
functions).
Name | Signature ( I -- O )
|
Description | Notes |
---|---|---|---|
tcp/ip
|
ip in -- out
|
Creates a TCP/IP socket connection with ip as the IP address and port, sends in in as the input in bytes, and returns out as the received output.
> "Running in 10.0.6.177:2763 is an echo server. (it echoes back the input given)" > [10 0 6 177 2763] iota 256 % tcp/ip 0 1 2 3 4 5 6 7 8 9 |
If the in iterator has been exhausted, the connection ends. Doing so also ends the out iterator.
Encountering out-of-range inputs also ends the connection. |
Format functions
These are functions that changes the I/O format of Iternary. They do not return anything, except /limit
which takes 1 input.
Name | Description |
---|---|
/unicode
|
Uses Unicode characters to represent an integer. |
/byte
|
Uses raw bytes to represent an integer. |
/number
|
Uses numbers to represent an integer. |
/space-seperated
|
Seperate numbers by spaces. This includes new lines. |
/null-seperated
|
Seperate numbers by null characters. |
/comma-seperated
|
Seperate numbers by commas. |
/line-seperated
|
Seperate numbers by new lines. |
/eof-ends
|
Encountering EOF ends the iterator generated by input .
|
/line-ends
|
Encountering a new line ends the iterator generated by input .
|
/null-ends
|
Encountering a null character ends the iterator generated by input .
|
/no-limit
|
Don't limit the output. |
/limit
|
Limit the output by the first value of the input iterator. |
Macros
Macros can be created by encasing them in { braces }
, preceded with the macro name.
Any further occurrences of the macro word would be substituted with the macro content.
> peek{ fork print } > iota peek 1 + 0 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 10
Store and recall
Iternary can store and recall iterators from the data table. They can be done by adding $
into the hash name.
Recalling iterators copies it into the stack.
> 5 jot a$ "sets slot 'a' to iterator [0 1 2 3 4]" > $a 0 1 2 3 4 > $a "Notice the iterator at slot 'a' has been exhausted from outputting it" > $b "By default, all slots contains an empty iterator" >
Execution
The Iternary interpreter has two stacks: the function stack that stores functions, and the data stack that stores iterators. When either an iterator or a function is pushed into their respective places, the data stack is checked if it has the amount the topmost function requires (for example, at least 2 values for a dyadic function). If it does, the topmost function is popped and executed. This is repeated until the data stack is exhausted (its size is smaller than the arity of the topmost function).
As such, stack underflows are impossible in Iternary. Functions with arity larger than the current data stack size would just be pushed into the function stack, instead of being executed directly. This also makes Iternary somewhat an ambifix language, since Iternary doesn’t really care where the function is written on the source.
> "These lines are equivalent in Iternary." > [2] [3] + "This form is recommended, though!" 5 > [2] + [3] 5 > + [2] [3] 5
In the end of a program (or the end of a line on the interactive prompt), the remaining iterators in the data stack are
popped and printed under a specific format. (/unicode /no-seperator /limit 40 /line-ends
by default)