Skip to content

Tutorial

ZippyMagician edited this page May 15, 2021 · 10 revisions

Arn tutorial

What follows is my best attempt at a tutorial for Arn. I'll try and cover everything that you'll need to actually write programs. For reference, see this page for a list of all symbols: their precedence, arg count, and description. You can also see this page for a list of built in functions and variables. This goes a lot more in depth then anything else on the wiki.

Basic types

Arn is composed of 3 basic types; strings, numbers, and sequences. Strings are composed simply by wrapping text in ".

Numbers are a little more complicated in Arn. They can be found in any of the following forms: 5, 5e3, e3, _5, _5e3, _5e_3, _e3. The _ attached to a number denotes a negative sign, and e{number} is how you write * 10 ^ {number} (the same as javascript).

Finally, sequences

Sequences

The most basic sequence in Arn is something such as this: [1 2 3 4]. This is a sequence with length of 4 that contains 4 numbers. For now, this is the only type that will be explained, as other concepts are required before showing the other forms sequences take

Groups

The term group is used in Arn to mark expression(s) wrapped in either [ ], { }, or ( ). Any group (or string) can have the closing character left off when at the end of the program or inside another group.

Anyway, we wil focus on ( ) first. After talking about expressions.

Expressions

An expression is a chain of symbols, such as 4 + 3 + 2 / 4. Due to how Arn parses expressions, if you want multiple expressions THAT INVOLVE OPERATIONS adjacent to one another, a , will do just that. For instance, 4 + 3, 2 + 1 will correctly evaluate to 7, 3, which just yields the last expression, 3.

Moving on

( ) is (also) called a group (sorry couldn't think of a better name). It works exactly as you expect. Take this math expression: 4 * 3 + 2. If you want to multiply 4 by 3 + 2, you would write 4 * (3 + 2) instead. These are very simple.

The next is { }, which are called blocks. The most basic block looks almost identical to a group, in that it wraps some number of expressions. So what's the purpose?

  • These can have a specific key attached to them.

When a block is evaluated, for example { + 3 }, it defaults to having a key of _ (this is the implied variable in Arn, we will talk about this in the next section). You can, however, provide it it's own key, which will allow you to prevent _ from being overriden by the block. This will allow referencing some value passed into the block as well as the global _.

Variables

_

This is the primary variable in Arn, implied. It is initialized to STDIN, and is implied whenever a value is missing from an operation. For instance, +3 is the same as _+3.

Other variables

To see other defined variables, see this page. You can define variables with this syntax:

a := b

where a is the variable name and b is the value it will hold. To define and call a function,

a := + 3
4 . a

will correctly output 7.

A small bit of advice: variables have no in-code differentiation from functions. Due to this, lets take the following example:

f := *\(~||[1]) ## The factorial function
_ := 5
f

What would happen? It's simple: f operates on the global scope, and so will assume the code really looked liked this:

_ . f

This means the program will return 120, allowing you to save a byte by leaving out the ..

Again, Sequences

Now we can explain the other two types of sequences. The first is finite, and is written like so:

[<EXPRESSION>? {BLOCK} -> <EXPRESSION>]

For example, the first 10 numbers in the Fibonacci sequence: [1, 1, {+} -> 10]. Now, this may seem confusing. "Doesn't {+} parse out to {_ + _}? That wouldn't work?" Instead, what Arn does is systematically replace each _ with the last value. So, given previous values in a sequence of [1, 2, 3], the block {+-} would evaluate to {3 + 2 - 1}.

Finally, the last form of sequences is simple. If you leave out the -> <EXPRESSION>, the sequence becomes infinite. So, an infinite Fibonacci sequence would be [1 1{+ (as there are no symbols used, the commas can be left off).

Symbols

Symbols have three characteristics; the identifier, the precedence, and the rank.

The identifier is how it's delimited in code, for example := or +.

The precedence is essentially PEMDAS for math but on a larger scale; every symbol has its own precedence.

Finally, rank controls how many expressions a symbol takes on either side of it. For instance, ! has the rank of 0-1 (one arg on the right) and &. has the rank of 0-3. You can view these all on this page.

Now, we can get into some example programs.

Programs

+

Very simple. Just doubles the input (parses out to _ + _). There is also a double fix, :+.

+\~

This is the one-range to _ folded with addition. For instance, the input 4 would parse out to +\[1 2 3 4] and then 1 + 2 + 3 + 4.

+{*2}\~

This showcases the other ability of \: it can map prior to folding. Keep in mind the symbol @ can also map.

Almost every symbol that binds some expression to a/some value(s) accepts items other than a block; however, \ must have a block if you want to map. For instance, @+1 will map over _ by adding one to each value, which with \ would have to be {+1}\. Furthermore, one must remember that @{+1} is still valid, and useful if you want to save a reference to the global _.

~@!%2

This program is an even-number sieve over the range [1, _]. It parses out to (~) @ {!(_ % 2)}. The input of 5, for example, would output

0
1
0
1
0

(We will talk about output after these programs)

::-.|=1

::      Group by (evaluate right, group if truthy)
  -       The two adjacent values subtracted
   .|       Absolute value (difference)
     =1   Equals one

For example, the input [1 2 3 5 4 7 6 5 2 5 8] will output

1 2 3
5 4
7 6 5
2
5
8

(More programs will be added)

Output

A string is outputted without the quotations around it (of course).

A number is slightly different. There is a command line argument, output-precision. If you leave it, any number over 999 or lower than 0.001 will be converted into a truncated scientific notation. To avoid this, one must use the -o / --oprecision option along with a larger number. Furthermore, internal precision is determined by -p / --precision, and is defaulted to 50.

Sequences are simpler in some aspects. A sequence is automatically newline-separated when outputted. If a sequence contains an inner sequence, that inner one is space-separated instead. For instance, [1 2] outputs as

1
2

[[1 2] [3 4]] outputs as

1 2
3 4

and [[1 2]] outputs as

1 2