13
\$\begingroup\$

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.

\$\endgroup\$
3
  • \$\begingroup\$ Are you trying to get tips to beat me in the golf? :P (I should probably look at the tips for Python page) \$\endgroup\$
    – hyperneutrino
    Commented Mar 28, 2017 at 13:49
  • \$\begingroup\$ Wow, a question from PCG.SE that got into the Hot Network Questions and is not a programming puzzle / challenge! :) \$\endgroup\$
    – Pedro A
    Commented Mar 28, 2017 at 17:22
  • 1
    \$\begingroup\$ @HyperNeutrino Shhh.... :) \$\endgroup\$
    – user41805
    Commented Mar 29, 2017 at 8:00

10 Answers 10

7
\$\begingroup\$

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] */
\$\endgroup\$
3
\$\begingroup\$

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
\$\endgroup\$
1
\$\begingroup\$

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]
\$\endgroup\$
2
  • \$\begingroup\$ Can you do if[_ in y] instead? \$\endgroup\$
    – user41805
    Commented Mar 28, 2017 at 13:23
  • \$\begingroup\$ @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). \$\endgroup\$
    – fergusq
    Commented Mar 28, 2017 at 13:27
1
\$\begingroup\$

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 */
\$\endgroup\$
1
\$\begingroup\$

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)]

\$\endgroup\$
2
  • \$\begingroup\$ Is it also possible to pass multiple parameters to functions without requiring parentheses? \$\endgroup\$
    – user41805
    Commented Apr 18, 2017 at 17:30
  • \$\begingroup\$ @KritixiLithos Yes. Eg. [a()|atan2 _,_] would be allowed. \$\endgroup\$
    – fergusq
    Commented Apr 18, 2017 at 17:34
1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

[]/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 */
`]
\$\endgroup\$
1
\$\begingroup\$

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 */
\$\endgroup\$
1
\$\begingroup\$

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[]
\$\endgroup\$
1
\$\begingroup\$

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"/";"
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.