Tips for golfing in Röda

12

2

Röda is a stream-based scripting language created by fergusq.

What general tips do you have for golfing in Röda? I'm looking for ideas that can which can be applied to code-golf problems and which are also at least somewhat specific to Röda (e.g. "remove comments" is not an answer).

Please post one tip per answer.

user41805

Posted 2017-03-28T11:45:30.867

Reputation: 16 320

Are you trying to get tips to beat me in the golf? :P (I should probably look at the tips for Python page) – HyperNeutrino – 2017-03-28T13:49:31.507

Wow, a question from PCG.SE that got into the Hot Network Questions and is not a programming puzzle / challenge! :) – Pedro A – 2017-03-28T17:22:09.907

1@HyperNeutrino Shhh.... :) – user41805 – 2017-03-29T08:00:54.367

Answers

7

Use underscores

This is probably the most important tip. Nearly every golfed Röda program uses underscores.

The underscore syntax is syntactic sugar for for loops. The following lines of code are equivalent:

ls""|fileLength x for x|sort|pull
ls""|fileLength _|sort|pull

Each underscore adds a new variable to an invisible for loop that is around the statement. The loop pulls one value from the stream for each variable/underscore and then repeats, until no values are left.

Underscores can be used anywhere in statements:

a[x:y+1]=[1]*(1+y-x) /* Sets range x..y (inclusive) */
seq x,y|a[_]=1       /* 6 bytes less */

If you must refer to the same underscore value more than once, or use the values in reverse order, you can put a number after the underscore:

a|[_^_1]  /* maps x to x^x */
a|[_2-_1] /* maps each pair (x,y) to y-x, eg. [1,2,4,8] -> [1, 4] */

fergusq

Posted 2017-03-28T11:45:30.867

Reputation: 4 867

3

Some semicolons/newlines are optional

When writing Röda code, it is generally recommended to use newlines or semicolons to separate all statements. However, when golfing, it is worth to know that not all semicolons are really required.

Here's an incomplete list of places where semicolons/newlines are optional. Most of them do not apply when the following statement begins with an operator ((, [, +, etc.).

  • After assignments
  • After function calls, when there's at least one argument (eg. f x) or when parentheses are used (eg. f())
  • Everywhere, if the next line/statement would begin with |, ), ] or }

If the next statement begins with an operator, the semicolon/newline is optional if

  • The statement is a function call and parentheses are used, eg {f(x)[y]} is same as {f(x);[y]}. This works only in statement context, not when the function call is an expression.
  • The statement is an assignment and parentheses are used, eg x=(y)[z] is same as x=(y);[z] (that is not same as x=((y)[z])).

And here are some places where the newlines are unfortunately required:

  • After ++ and --.
  • After [...].

It is often possible to save bytes by reorganizing assignments. For example:

a=0;b=""c=[""]
b=""c=[b]a=0

x=f()y=i;z=a[0]
x=f()z=a[0]y=i

fergusq

Posted 2017-03-28T11:45:30.867

Reputation: 4 867

1

Use suffix control structures

It is almost never optimal not to use suffix statements, as you can use {...} in place of do...end.

Some examples:

x|unless[not(_ in y)]do[0]else[1]done
x|[0]unless[not(_ in y)]else[1]

if[p<0]do c+=p;a-=p done
{c+=p;a-=p}if[p<0]

fergusq

Posted 2017-03-28T11:45:30.867

Reputation: 4 867

Can you do if[_ in y] instead? – user41805 – 2017-03-28T13:23:46.750

@KritixiLithos No, because I want the condition to be OR, not AND. Currently it checks if there is at least one value in x that is also in y, but your condition would check if all values in x are also in y. (The example was copied from here).

– fergusq – 2017-03-28T13:27:17.357

1

Use the stream for input

In cases where the input is a list of elements, it can be beneficial to pull the values from the stream instead of getting them as an array.

In most of the cases the array elements are iterated by pushing them to the stream and then iterating it using a for loop (or an underscore). As the elements are iterated from the stream anyway, why not define that they should be there from the beginning?

For example, to calculate the sum of the squares of the numbers in input:

{|a|a|[_^2]|sum} /* Removing a redundant argument */
{[_^2]|sum}      /* saves 5 bytes */

fergusq

Posted 2017-03-28T11:45:30.867

Reputation: 4 867

1

Using `` strings

In "" strings, you will have to escape certain characters in order to use them. For example, to print the backslash, you would have to have a string like "\\". There is one added byte for escaping the backslash. However, if you use ``, you do not have to escape this character and can save one byte.

print"\\"     /* 9 bytes */
print`\`      /* 8 bytes */

Not just that, you can encode variables and expressions inside of `` strings using $variableName or ${expression}, a feature not present in "" strings.

We are outputting the string "a" concatenated with the value of the variable b with a trailing newline in these examples.

["a",b,"      /* 11
"]               bytes   */
[`a$b         /* 8
`]               bytes; encodes b in the string using $b */

user41805

Posted 2017-03-28T11:45:30.867

Reputation: 16 320

1

Use , instead of and

Conditions in Röda are streams, and can consist of multiple values. These values are reduced to one boolean value with and.

This means that you can replace and with , in conditions to push multiple values to the stream:

x if[a and b]
x if[a,b]

Empty condition is truthy

It is also possible to have a condition that contains no values, which is truthy.

x while true
x while[]

fergusq

Posted 2017-03-28T11:45:30.867

Reputation: 4 867

1

The parentheses are optional in the statement context. This applies even if the argument begins with an operator. For example, [a()|sqrt-_] is shorter than [a()|sqrt(-_)]. The parentheses after a are mandatory, as a is in the expression context, not in the statement context.

However, writing [a()|sqrt(_+1)*2] is not possible, and extra parentheses are needed to help the parser: [a()|sqrt((_+1)*2)]. Often it is possible to rewrite such expression so that it doesn't begin with a parenthesis: [a()|sqrt 2*(_+1)]

fergusq

Posted 2017-03-28T11:45:30.867

Reputation: 4 867

Is it also possible to pass multiple parameters to functions without requiring parentheses? – user41805 – 2017-04-18T17:30:10.780

@KritixiLithos Yes. Eg. [a()|atan2 _,_] would be allowed. – fergusq – 2017-04-18T17:34:53.053

1

Use , instead of .. in []/push statements

Related: Use , instead of and

The push function (as well as the print function) can take any number of arguments, and outputs each one of them with no delimiter.

So that means something like this

["a"..b]        /*8 bytes (string "a" concatenated with variable b)*/

can be shortened into just

["a",b]         /*7 bytes*/

saving 1 byte.

user41805

Posted 2017-03-28T11:45:30.867

Reputation: 16 320

1

[]/push > print

Never use print statements. [] push statements are always golfier. The difference between print and push is that the former outputs a trailing newline while the latter doesn't. However, this can be circumvented.

print"a"              /* 8 bytes */
["a                   /* 6 bytes; uses a literal newline */
"]

print"a",b            /* 10 bytes */
[`a$b                 /* 8 bytes; uses a literal newline and `` strings */
`]

user41805

Posted 2017-03-28T11:45:30.867

Reputation: 16 320

1

Write replacement lists in form *"...;..."/";"

The replace function takes normally a list of strings as arguments. However, if the list is very long, it is beneficial to simply store the regex/replacement pairs in a string and then split the string and use the star operator:

replace"a","b","c","d"
replace*"a;b;c;d"/";"

fergusq

Posted 2017-03-28T11:45:30.867

Reputation: 4 867