rrreplace

From Esolang
Jump to navigation Jump to search

rrreplace is an esoteric language that uses string substitution in a functional way.

Specification

Syntax and semantics

Functions

Each rrreplace program is a list of functions. They are written as follows:

<function name>=<expression>

A function name can contain any letters, numbers, and special characters. If you use special characters like {, : or }, you will have to escape them whenever you call the function, but they are valid nevertheless. The main function has an empty string as the function name. This function is called when the program runs.

Expressions

Each expression is written in the following form: {~foo:foo:bar:0:1} It starts with a { and ends with a }. The first character after the { is the instruction. Then the different arguments are put there, separated by a :

Note that both the instruction character and the different parameters can be expressions themselves. If there are unescaped expressions inside an expression, they are resolved first. Note that some instructions use lazy evaluation, so if the value of a certain argument might not be needed, an expression standing there will not be resolved.

The basic expression are {(}, {)} and {:}. These will resolve to {, } and : but can be used to escape these characters inside of expressions.

Note that if a result of an expression contains any of these three special symbols, the resulting expression will also have these escaped. Note that even if we will use \: in this article to mean the escaped version of :, syntax wise, backslash does not escape characters. (This is actually implemented in the tokeniser, just disabled, as the other versions of escape are more in the spirit of the language.)

Function instructions

There are two important instructions related to function calls, $ and @.

$ takes one single argument. It resolves to the n-th parameter of the currently executing function.

@ takes many arguments. The first argument is the function name, and all other arguments are the parameters.

For example, if we want to make a function that repeats a string twice, we can write it like:

double={$0}{$0}

And we can call it like

={@double:abc}

Running the full program will produce abcabc.

Using $ in the main function will use command line parameters instead of function parameters.

It is possible to pass 2 arguments to $, then it will give a range of arguments, seperated by :

Evaluate instructions.

& takes one argument as a string. It resolves its first argument as an expression.

All arguments of an expression and even the instruction character itself can already be expressions, so the only reason to use this ever is if you want to unescape braces (where you dynamically build nested expressions) or separators (when working with map-reduce or recursion).

Let's look at an example:

This program:

test=1:2:3 
collapse={$0}{$2}{$1} 
={@collapse:{@test}}

Will not work. {@test} resolves to 1\:2\:3, and collapse will not have enough arguments.

But

test=1:2:3 
collapse={$0}{$2}{$1} 
={&@collapse{:}{@test}}

does work, cause @collapse{:}{@test} resolves to @collapse:1:2:3 which can be executed to produce 132.

As & only takes one argument, it automatically escapes any : inside it brackes, so we might as well write @collapse:{@test}

& will allow a substring to close and reopen itself, but not its parent.

So for example:

{&$0{)}-{(}$1} will be valid, and be equivalent to {$0}-{$1}, but {&$0{)}{)}-{(}{(}$1} is not valid.

SplitJoin.

~ is the 'splitjoin' statement. It takes five arguments, "string", "split", "join", "start", and "stop".

It takes the following actions:

  1. split the string using "split"
  2. select the arguments from start to stop
  3. joins the string using "join".

For example {~a.b.c.d.e:.:_:1:3} will return b_c.

Start and stop can be omitted to mean the beginning/end of the string.

If both are omitted splitjoin will act as a replace.

Sieve

# is the sieve statement. It will return all characters in the first argument in order, that appear in the second argument.

For example

{#a_b.c_d:_.}

will return _._

Burn

^ is a burn statement. It will replace the second argument with the third as long as it exists.

For example

{^aaaaxbbab:axb:x}

will result in aaxab

Multiply

The * instruction will return the first argument the second argument times. If the second argument is omitted, it will count the number of characters in the first argument.

For example

{*abc:2}

will return abcabc

and

{*abc}

will return 3

conditional

The ? instruction will return the second argument if the first argument is non-empty, and the third argument otherwise.

Examples

Hello world

=Hello world!

Just return hello world. very easy

Cat

={$0}

Just return the first argument

Sum

This program will sum the two first elements it receives together and leaves the others unaltered

sum={*{*a:{$0}}{*b:{$1}}} 
={@sum:{$0}:{$1}}:{$2:}

Map

Increases all the numbers provided with one, independent of the number of arguments.

incr={*a{*a:{$0}}} 
map={&{$1}{:}{~{$0}:{:}:{)}{:}{(}{$1}{:}}} 
={@map:{$:}:@incr}

Reduce

Adds all numbers using reduce.

sum={*{*a:{$0}}{*b:{$1}}} 
basecase={?{#{$:}:{:}}:{&@reduce:{$:}}:{$0}} 
reduce={@sum:{$0}:{&@basecase:{$1:}}} 
={&@basecase:{$:}}

Note that while this is easy to extend to other functions, there is a simpler way to add a sum over multiple elements:

map*={&*a:{~{$0}:{:}:{)}{:}{(}*a{:}}} 
={*{#{@map*:{$:}}:a}}

Language Implementation

An interpreter for this language written in python can be found here: [1]