MoreMathRPN

From Esolang
Jump to navigation Jump to search
MoreMathRPN
Paradigm(s) imperative, functional
Designed by User:Calculus is fun
Appeared in 2023
Computational class Turing-Complete
Major implementations JavaScript
Influenced by FALSE, TI-BASIC
2 M's are placed above the letters "RPN" all in black, placed into a light blue to blue gradient top to bottom
Logo for MoreMathRPN
Unless otherwise specified, "or" is exclusive or.

MoreMathRPN (abbreviated MMRPN) is a stack based imperative language created in 2023, created by Calculus is fun (talk).
Originally for simple linear algebra, it has since grown to be turing complete. It is inspired by FALSE and its relatives, whilst also being more human friendly.

Using relative offsets over absolute positions is the primary philosophy of MMRPN, no labels, nor line numbers.

Commands

Each line must have only one command, breakpoint, or comment.
While not part of the standard, MMRPN reserves "!!!" to be a breakpoint, if you write an interpreter or compiler, your code should at least behave like a breakpoint and its line doesn't exist

Literals

This language has rational and string literals, there are 4 ways to input a Rational:

  • Integers e.g. 10
  • Ratio of 2 integers e.g. 3/5
  • Terminating decimal e.g. 3.894
  • Recurring decimal e.g. 1.1[32] -or- 0.[3]

You can prepend a hyphen to negate the value, and periods can be substituted with commas.
String literals can only be in an instruction's parameters,
they are double quoted strings that allow spaces; most literal UTF-8 characters; along with \\, \", and \n escape characters.

Instructions

There are 2 types of input a command has, Parameters and Arguments. Parameters are integers placed after the command and separated by spaces. Arguments are from the stack and can be rational (R) or matrices (M), if needed; variables will be denoted [top] a, b, c, ... [bottom]

Standard operations

Operation symbol/name Description / Formula Parameters Arguments
" Comment (see examples below) None None
+ Addition None 2 R or 2 M
- Subtraction (b - a) None 2 R
* Multiplication None 2 R, 2 M, or 1 R and 1 M
/ Division (b / a) None 2 R
% Remainder (b % a) None 2 R
int Integer part None 1 R
floor Round down None 1 R
ceil Round up None 1 R
den Denominator None 1 R
gcd Greatest common divisor None 2 R
lcm Least common multiple None 2 R

Checks and comparisons

Operation symbol/name Description / Formula Parameters Arguments
# Stack height None None
step Greater than zero (a > 0 → 1, a <= 0 → 0) None 1 R
hyperStep Divides by infinity, by cheating
(a == -∞ → -1, a == ∞ → 1, otherwise → 0)
None 1 R
compare Comparison (a > b → -1, a == b → 0, a < b → 1) None 2 R
query looks at an element in the stack whose depth is given by the parameter, if it's rational then outputs 0, if it's a matrix, outputs 1 Depth None

Stack manipulation

Operation symbol/name Description / Formula Parameters Arguments
>> Copy Depth None
-> Pull Depth None
<- Push Depth None
del Delete Depth None

Matrices

Operation symbol/name Description / Formula Parameters Arguments
m Matrix Columns, rows columns * row R
unzip Inverse of m command None 1 M
addRow Row addition Row from, row to 1 R and 1 M
scaleRow Row scaling Row 1 R and 1 M
swapRows Row swapping Row from, row to 1 M
T Transpose None 1 M
inv Inverse None 1 R or 1 M
ref Row echelon form None 1 M
ind Value at index Column, row 1 M
rip Rip last column None 1 M
flip Flip across rows None 1 M
dim Dimensions None 1 M
dot Dot product None 2 M
hadamard Hadamard product None 2 M
kronecker Kronecker product None 2 M
outer Outer product None 2 M

Loops

Operation symbol/name Description / Formula Parameters Arguments
jmp Jump to Offset None
repeat Repeat loop End Count None
next Next iteration None None
>>> Iteration number Loop Depth None
break Break out of current loop None None
leap Break out of current loop, then jump Offset None

Variables

Variable names can not have spaces nor start with ".

Operation symbol/name Description / Formula Parameters Arguments
hold Store top of stack as variable Name 1 R or 1 M
place Place copy of variable to stack Name None
lose Remove a variable Name None
exists Exists (does variable exist? yes → 1, no → 0) Name None

IO & strings

Operation symbol/name Description / Formula Parameters Arguments
chars Converts a string's UTF-8 code points in reverse order (end is at the bottom), then tops it with the string's length. String None
inputR Prompts the user to input a number in a valid format as described above, if invalid, the program will ask again.
The prompt message is an optional parameter, and not giving it should default to a generic message.
Prompt (optional) None
inputS Prompts the user to input a string, converts the response's UTF-8 code points in reverse order (end is at the bottom), then tops it with the string's length.
The prompt message is an optional parameter, and not giving it should default to a generic message.
Prompt (optional) None
inputSE Prompts the user to input a string potentially containing escaped characters (especially \n & \\), converts the response's UTF-8 code points in reverse order (end is at the bottom), then tops it with the string's length.
The prompt message is an optional parameter, and not giving it should default to a generic message.
Prompt (optional) None
outputC Outputs a single character whose code point is the parameter Code point None
outputS Outputs a string String None
outputV Pops and outputs a rational or matrix, format depends on implementation None 1 R or 1 M
error Outputs a string as an error message, and stops execution String None

Lambda functions

Operation symbol/name Description / Formula Parameters Arguments
run interprets a row matrix as a string, then interprets the string None 1 M (single row)
end Stops the current program, useful with run commands None None
halt Halt and catch fire none none

Tip: I recommend you write any code normally, place chars " before the first instruction then use a macro that presses the End, Delete, \, n keys in that order exactly once. AutoHotKey is great for this.

Notes on recursion

While recursion is allowed with run, please avoid deep recursion, instead use a system akin to the first #Ackermann function example, with a return path using jmp.

The run command should only be used if:

  • You're calling a sequence of commands multiple times, in different contexts (i.e. both inside and outside a repeat...next block).
  • You need to jump over a code block that can be changed by another person.
  • A function is a parameter of another function, like Array.reduce().

Dynamic parameters

You might be thinking how if-else statements are going to happen in this language; fortunately, parameters can be controlled by the program, these get rounded towards 0 if the rational is not an integer.

  • ]n grabs the nth item from the top of the stack
  • [n grabs the nth item from the bottom of the stack
  • $name uses a variable

Behavior

Certain commands have specific actions given interesting conditions, here's a list of those conditions.

Infinity

In normal mathematics, dividing by zero (0) is disallowed, due to inevitable paradoxes that occur, but guess what? This is a programming language, where having a value of greater magnitude is useful! so infinity is here:

"Positive infinity
1/0
"Negative infinity
"-1/0

While Infinity does work in other situations, it gets real weird. If you subtract infinity from infinity, multiply infinity by zero, or other zany operations, you'll run into a special "Indeterminate form" error, when MMRPN can't give a good answer.

Repeat without next

If a repeat is missing a corresponding next, It is inferred to be at the end of the program, but the loop won't repeat. Either break or leap will end the program if run in an incomplete repeat statement.

repeat 10
 3
 5
 break
 5
 1
 "next statement inferred here!

Nested loops

repeat ... next blocks can be nested, helpful for simplifying advanced patterns

repeat 10
 repeat 10
  "outer
  >>> 1
  "inner
  >>> 0
  +
  2
  -
 next
next
m 10 10

Out of the loop

calling break or leap outside the active loop results in an error.
It is recommend to keep looping code in the repeat...next block.

repeat 10
 jmp 2
next
"Error!
break

Leaping back

leap with a negative parameter behaves like break, this is to dissuade the act of jumping into the repeat you just left.

"You would expect this to be an infinite loop, but it isn't.
repeat 1
 "I'm now a break!
 leap -2
next

Zero jmp

When jmp is given a parameter of 0, jmp does nothing, this is so you don't have to write 1 + every time you use it. See examples below.

Examples

More examples can be found here

Creating conditions

Conditions are often created via the step or compare instructions, then by evaluating an polynomial function and feeding that into a jmp, complex branching behavior can appear.

"change me to 1, 2 or 3
1
"1 → "1", 2 → "21", 3 -> "31"
>> 0
>> 0
*
-2
/
-> 1
2
/
4
+
+
jmp ]0
outputS "3"
jmp 2
outputS "2"
outputS "1"

You can also use repeat with a parameter of 1 or 0, to run or skip a block of lines.

"0 or 1
0
repeat ]0
 1
 2
 3
 4
 "dummy
 1
next
del 0

Fibonnaci

This program repeatedly adds the previous 2 numbers forever

0
1
>> 1
>> 1
+
jmp -3

We can use the repeat instruction to limit the repetitions

0
1
"repeat 50 times...
repeat 50
 "indentation of code is optional, but preferred
 >> 1
 >> 1
 +
next

Factorial

Calculating the factorial is also easy

"argument
5
1
repeat ]1
 >>> 0
 *
next
del 1
"120 should be alone

Coefficients of a cubic

Using the matrix commands, one can solve a linear system quickly.

"degree + 1
repeat 4
 1
 >>> 0
 1
 -
 "degree
 repeat 3
  >> 1
  >> 1
  *
  -> 1
 next
 del 0
 m 1 4
next
"degree
repeat 3
 aug
next
T
flip
inv
"f(0)
0
"f(1)
1
"f(2)
4
"f(3)
-13
m 1 4
*
"x^3, x^2, x^1, x^0

Cat

Takes the input and returns it; Unless you send the empty string, then it terminates.

inputS
hold len
step
3
*
jmp ]0
del 0
jmp 7
del 0
repeat $len
 outputC ]0
 del 0
next
jmp -13

99 bottles of beer

Use the IO commands and get very hammered.

99
repeat 97
 >> 0
 >> 0
 1
 -
 >> 0
 <- 3
 <- 3
 outputV
 outputS " bottles of beer on the wall,\n"
 outputV
 outputS " bottles of beer.\nTake one down pass it around,\n"
 outputV
 outputS " bottles of beer on the wall.\n"
next
del 0
"Deal with singular bottle.
1
2
2
outputV
outputS " bottles of beer on the wall,\n"
outputV
outputS " bottles of beer.\nTake one down pass it around,\n"
outputV
outputS " bottle of beer on the wall.\n"
1
1
outputV
outputS " bottle of beer on the wall,\n"
outputV
outputS " bottle of beer.\nTake one down pass it around,\nOops, we ran out of beer!"

Using run

With the assistance of other commands, you can create functions with a similar syntax to FALSE.

chars "outputS \"Hello, world!\""
hold len
del 0
m $len 1
flip
hold hello
del 0
"...
place hello
run

You can also use aug in various ways to create dynamic functions, such as creating unique variable names

Fractran interpreter

It's fitting that a language based on rationals can run Fractran. Here's John Conway's prime program.

"program
17/91
78/85
19/51
23/38
29/33
77/29
95/23
77/19
1/17
11/13
13/11
15/14
15/2
55/1
#
hold len
del 0
m $len 1
"input
2
"loop
-> 1
>> 1
repeat $len
 "read fraction
 >>> 0
 1
 -
 -> 2
 ind ]1 0
 -> 1
 <- 3
 del 1
 "check validity
 >> 1
 *
 >> 0
 1
 %
 step
 2
 *
 jmp ]0
 "success
 leap 2
 "failure
 del 0
 del 0
next
"exit
jmp 4
"update input
del 0
del 1
"iterate again
jmp -27

Because we can run Fractran directly, this proves MMRPN is Turing-complete

Brainfuck interpreter

It is quite monstrous, at 356 lines, I put it in it's own section: go view it →

Quine

I have 2 quines available for you, again they are big, so here's another section: go view it →

Implicit plotter

Want to use the worst plotter know to man? Yes? Ok then, take a look →

Ackermann function

This function requires recursion; with a little planning however, you can use the stack as a call stack too!

"m
3
"n
3
"----
43
jmp 3
"return path
-> 1
jmp ]0
"begin A(m,n) form m, n, return location
<- 2
"m==0
>> 1
step
6
*
jmp ]0
"true
del 0
"n + 1
del 1
1
+
"return
jmp -12
"false
"n==0
del 0
>> 0
step
10
*
jmp ]0
"true
del 0
del 0
1
-
1
25
"A(m-1,1)
jmp -23
del 0
"return
jmp -27
"false
del 0
>> 1
-> 1
1
-
34
"A(m, n-1)
jmp -32
del 0
-> 1
1
-
-> 1
41
"A(m-1,A(m,n-1))
jmp -39
del 0
"return
jmp -43
"end A(m,n)
del 0
outputV

If you want to use run:

3
3
outputS "A("
>> 1
outputV
outputS ", "
>> 0
outputV
outputS ")"
chars ">> 1\nstep\n6\n*\njmp ]0\ndel 0\ndel 1\n1\n+\nend\ndel 0\n>> 0\nstep\n9\n*\njmp ]0\ndel 0\ndel 0\n1\n-\n1\nplace Ackermann\nrun\nend\ndel 0\n1\n-\n>> 1\n1\n-\n<- 2\nrepeat 2\nplace Ackermann\nrun\nnext\nend"
hold Ackermann
del 0
m $Ackermann 1
flip
hold Ackermann
run
outputS " = "
outputV

Examples elsewhere on this site

Implementations

JavaScript MMRPN Interpreter by Calculus is fun (talk)!