Uiua An array-oriented tacit programming language
Support Uiua's development Home
Back to Docs Home
〈 Previous: Modifiers and Functions Next: Inverses 〉
Advanced Stack Manipulation
Uiua does not have local variables. With only . duplicate , : flip , and
, over , how do you work with more than 2 values at a time?
⊃ fork
⊃ fork is a dyadic modifier that takes 2 functions and calls them both on
the same set of arguments. The number of arguments used is the maximum
of the two functions.
1 [⊃+× 3 5] � ↧ �
[8 15] Run
If one of the functions takes more arguments than the other, the function
with fewer arguments uses the top-most values.
1 ⊃×⇌ [1 2 3] 10 � ↧ � 1/3
[3 2 1] Run < >
[10 20 30]
What's powerful about ⊃ fork is that it can be chained to use as many
functions as you want.
1 [⊃⊃⊃+-×÷ 5 8] � ↧ �
[13 3 40 1.6] Run
⊃ fork is also good because it does not require that its values be in an
array together, so they can be different shapes or types.
1 ⊃+- 1 @b � ↧ � 1/3
@a Run < >
@c
1 ⊃⊃⊃↻↙↘⊡ 2 [1 2 3 4 5] � ↧ � 1/3
3 Run < >
[3 4 5]
[1 2]
[3 4 5 1 2]
We'll see just how important ⊃ fork is later in this section.
both
both is a monadic modifier and a sort of complement to ⊃ fork . While
⊃ fork calls multiple functions on the same set of arguments, both
calls a single function on multiple sets of arguments.
1 ⇌ [1 2 3] [4 5 6] � ↧ � 1/3
[6 5 4] Run < >
[3 2 1]
Chaining both doubles the number of arguments each time.
1 ⇌ [1 2 3] [4 5 6] [7 8 9] [10 11 12]
� ↧ � 1/5
[12 11 10] Run < >
[9 8 7]
[6 5 4]
[3 2 1]
⊓ bracket
To round off the trio, we have ⊓ bracket , which is a dyadic modifier that
calls each of its functions on a different set of arguments.
1 [⊓+× 1 2 3 4] � ↧ �
[3 12] Run
⊓ bracket too can be chained. Each additional function is called on
arguments deeper in the stack.
1 [⊓⊓⊓+¯×. 1 2 3 4 5 6] � ↧ �
[3 ¯3 20 6 6] Run
Function Packs
All dyadic modifiers allow a special notation with a single set of () s with a
| in the middle separating the functions. This is called a function pack.
1 ⊓(+|×) 1 2 3 4 � ↧ � 1/5
12 Run < >
3
While all dyadic modifiers can use function packs, ⊃ fork and ⊓ bracket
allow more than 2 functions to be used. This can sometimes be shorter
and/or more readable than chaining the modifier.
1 [⊃(+|-|×|÷) 5 8] � ↧ �
[13 3 40 1.6] Run
1 [⊓(+1|×|÷2) 5 10 12 22] � ↧ �
[6 120 11] Run
⊙ dip
The ⊙ dip modifier temporarily pops the top value on the stack, calls its
function, then pushes the value back.
1 [⊙+ 1 2 3] � ↧ �
[1 5] Run
⊙ dip can be chained to dig deeper into the stack, though try not to dig
too deep, as it makes code harder to read.
1 [⊙⊙⊙⊙⊙⊙+ 1 2 3 4 5 6 7 8] � ↧ �
[1 2 3 4 5 6 15] Run
One use of ⊙ dip is to collect values from the stack into an array. Here, a
chain of ⊙ dip s are terminated with ∘ identity .
1 [⊙⊙⊙∘] 1 2 3 4 5 � ↧ � 1/6
5 Run < >
[1 2 3 4]
1 {⊙⊙∘} 1 2_3 "wow" � ↧ � 1/4
{1 [2 3] "wow"} Run < >
However, you do not typically need to do this because of...
Subscripts
Subscripts are a special syntax that allows you to augment some functions
and modifiers with a number.
Subscripts are typed with __ followed by some digits. The formatter will turn
them into subscript digit characters. A leading negative sign is allowed.
Several functions and modifiers are supported, but we'll only cover some
stack-related ones here. You can find a full list of subscript-compatible
functions here.
Subscripted both calls its function on N sets of arguments.
1 [ + 1 2 3 4] � ↧ � 1/3
2 [ + 1 2 3 4 5 6]
3 [ + 1 2 3 4 5 6 7 8] # Try formatting!
[3 7] Run < >
[3 7 11]
[3 7 11 15]
Subscripted ⊟ couple collects N values from the stack into an array.
1 1 2 3 4 5 � ↧ � 1/6
5 Run < >
[1 2 3 4]
□ box has similar behavior, but it boxes each value.
1 □₃ 5 "Hi!" [1 2 3] � ↧ � 1/4
{5 "Hi!" [1 2 3]} Run < >
� Planet Notation �
⋅ gap discards the top value on the stack and calls its function.
1 ⋅+ 1 2 3 � ↧ � 1/4
5 Run < >
But wait, ◌ pop exists! Why would you need this?
The main reason for ⊙ dip and ⋅ gap to exist is to be chained with
∘ identity , often inside of ⊃ fork . They act as a sort of boolean
selector to choose which arguments to keep and which to discard in a
branch.
This is called planet notation because it looks like the planets in a solar
system chart.
For example, let's say you want to × multiply the 2nd and 4th arguments
on the stack and discard the rest:
1 ×⋅⊙⋅∘ 1 2 3 4 � ↧ � 1/6
8 Run < >
Notice how the circles correspond to the stack arguments we want.
Maybe you want to + add 3 numbers but keep the second 2 on the stack:
1 [⊃⋅⊙∘(++)] 2 5 10 � ↧ � 1/4
[5 10 17] Run < >
You can read ⋅ ⊙ ∘ as "discard argument 1, keep argument 2, keep
argument 3."
If you only wanted to keep argument 2, you simply make the expression
shorter:
1 [⊃⋅∘(++)] 2 5 10 � ↧ � 1/4
[5 17] Run < >
For a more useful example, let's do a complex mathematical expression. We
will implement this function (shown here in mathematical notation):
f(a,b,c,x) = (a+x)(bx-c)
We'll start with the (a + x) part. We can grab a and x with ⊙ dip and
∘ identity , and ignore b and c with ⋅ gap .
1 +⊙⋅⋅∘ 1 2 3 4 � ↧ � 1/6
5 Run < >
Next, we'll do the (bx-c) part. We can grab each term with ⊃ fork .
1 -⊃(⋅⋅∘)(×⋅⊙⋅∘) 1 2 3 4 � ↧ � 1/6
5 Run < >
The first pair of () s is not actually necessary, so let's remove them.
1 -⊃⋅⋅∘(×⋅⊙⋅∘) 1 2 3 4 � ↧ � 1/6
5 Run < >
Finally, we can combine the two parts with another ⊃ fork .
1 ×⊃(+⊙⋅⋅∘)(-⊃⋅⋅∘(×⋅⊙⋅∘)) 1 2 3 4 � ↧ � 1/6
25 Run < >
If you like, you can factor out the ⋅ gap in the second part
1 ×⊃(+⊙⋅⋅∘)⋅(-⊃⋅∘(×⊙⋅∘)) 1 2 3 4 � ↧ � 1/6
25 Run < >
Alternatively, you can use a function pack.
1 ×⊃(+⊙⋅⋅∘|-⊃⋅⋅∘(×⋅⊙⋅∘)) 1 2 3 4 � ↧ � 1/6
25 Run < >
And there you have it! A readable syntax juggling lots of values without any
names!
It's annoying to write long lists of names like gapdipgapgapide , so those
three functions (plus ◌ pop ) have a special rule in the parser that allows you
to write them with only 1 character as long as there are at least 2 characters
in the sequence. Also, 'i' and 'p' for ∘ identity and ◌ pop only work if
they are the last character.
Try it out!
1 +gdggi 1 2 3 4 5 � ↧ � 1/7
7 Run < >
1 +dggdp 1 2 3 4 5 � ↧ � 1/7
5 Run < >
In general, planet notation as complex as the mathematical function example
above should only be used when it is necessary. For examples like that with
4+ values, it is. However, when working with fewer values, you can get very
far with just . duplicate and : flip . Maybe sprinkle some , over s
and ⊙ dip s in there too.
⟜ on and ⊸ by
As you write more Uiua code, you'll find that there is a kind of pattern you'll
encounter over and over again. It involves calling a function, then calling
another function that re-uses an argument to the first function.
One simple example is getting n numbers between 0 and 1 . One way you
may think to solve this is with . duplicate and : flip .
1 ÷:⇡. 5 � ↧ � 1/5
Style: Prefer ⟜ over : . here Run < >
at 1:2
1 | ÷:⇡. 5
───
[0 0.2 0.4 0.6 0.8]
This solution works, but as the style diagnostic suggests, it is not quite
idiomatic.
When the first function you call is dyadic, it can get a little trickier. For
example, if you wanted to get all the integers between two numbers, you
may try either of the following:
1 +⇡-,: 3 8 � ↧ � 1/11
2 +⊃∘(⇡-) 3 8
Style: Prefer `⟜:` over `,:` for clarity Run < >
at 1:4
1 | +⇡-,: 3 8
──
Style: Prefer `⟜` over `⊃∘` for clarity
at 2:2
2 | +⊃∘(⇡-) 3 8
──
[3 4 5 6 7]
[3 4 5 6 7]
Again, as the style diagnostics tell you, there is a better way.
The ⟜ on modifier calls a function but keeps its first argument on top of the
stack. This can be used in both of the above examples.
1 ÷⟜⇡ 5 � ↧ � 1/3
[0 0.2 0.4 0.6 0.8] Run < >
1 +⟜(⇡-) 3 8 � ↧ � 1/4
[3 4 5 6 7] Run < >
Having a single glyph for something that can be written as simply ⊃ ∘ may
seem unnecessary, but you'll find that because the pattern is so common, it
makes code easier to both read and write.
The ⊸ by modifier is similar. Instead of keeping the first argument on top of
the stack, it keeps the last argument below the function's outputs.
1 ÷⊸⧻ [1 2 3 4] � ↧ � 1/3
[0.25 0.5 0.75 1] Run < >
1 ▽⊸> 5 [1 8 4 9 2 8 4] � ↧ � 1/4
[8 9 8] Run < >
Challenges
Challenge 1
Write a program that moves the 4th value on the stack to the top.
1 � ↧ �
Run
Example: 1 2 3 4
3
2
1
4
Input: @x [1 2 3] □5 27
27
□5
[1 2 3]
@x
��
Challenge 2
Write a program that adds the second argument to the third and divides
by the first.
1 � ↧ �
Run
Example: 2 3 5
4
Input: 1 2 3
3
2
1
Input: 5 10 15
15
10
5
Challenge 3
Write a program that finds both the sum and product of three arguments.
1 � ↧ �
Run
Example: 4 5 6
120
15
Input: 10 10 10
10
10
10
Input: 1_2 3_4 5
5
[3 4]
[1 2]
Challenge 4
Write a program that collects 9 values from the stack evenly into 3 arrays.
1 � ↧ �
Run
Example: 1 2 3 4 5 6 7 8 9
[7 8 9]
[4 5 6]
[1 2 3]
Input: @G @o @o @d @ @j @o @b @!
@!
@b
@o
@j
@
@d
@o
@o
@G
Input: ...×2..+1...5
5
5
5
6
6
12
12
12
12
Challenge 5
Write a program that for numbers A, B, C, and D calculates (A+C)×(B+D).
1 � ↧ �
Run
Example: 1 2 3 4
24
Input: 10 ¯3 1 0
0
1
¯3
10
Input: 3 ¯7 2 2
2
2
¯7
3
��
〈 Previous: Modifiers and Functions Next: Inverses 〉
Back to Docs Home