As the June 2021 Language of the Month is Red, what are some general tips for golfing in Red language?
Please suggest tips that are at least somewhat specific to Red (e.g. "remove comments" isn't a valid tip here).
Please one tip per answer!
As the June 2021 Language of the Month is Red, what are some general tips for golfing in Red language?
Please suggest tips that are at least somewhat specific to Red (e.g. "remove comments" isn't a valid tip here).
Please one tip per answer!
In Red you usually use to <type> <spec>
or the predifined to-<type> value
functions:
>> to integer! 3.14
== 3
>> to-integer 2.71
== 2
>> to char! 65
== #"A"
>> to-integer #"A"
== 65
<type>
can be a datatype or an example value (a prototype). That's why we can shorten the above examples as follows:
>> to 1 3.14
== 3
>> to 0 2.71
== 2
>> to sp 65 ; sp is space = #" "
== #"A"
>> to 1 #"A"
== 65
Of course this can be applied to all datatypes that have literal representation:
>> to[]123 ; to block! 123
== [123]
>> to""[123] ; to-string [123]
== "123"
>> to 1-1-1[2 6 2021]; to-date [2 6 2021]
== 2-Jun-2021
>> to now[2 6 2021]
== 2-Jun-2021
>> to 0.0.0[255 0 0] ; to tuple! [255 0 0]
== 255.0.0
>> to sky[255 228 196] ; sky is a predifined color 164.200.255 (a tuple!)
== 255.228.196
>> to 1x1[-10 42]; to-pair [-10 42]
== -10x42
>> to#{}"string"; to-binary "string"
== #{737472696E67}
do"123"
, which evaluates the string as code.
\$\endgroup\$
Commented
Jun 8, 2021 at 7:22
do
?
\$\endgroup\$
Commented
Jun 8, 2021 at 7:24
do
do
is Red's equivalent of an eval
command. It evaluates code as a string. It is useful when wanting to convert a string to an integer (or any valid Red expression):
to-integer n # The obvious way
to 0 n # From @GalenIvanov's type casting tip
do n # `do` is shortest
form
the block into a string (form
returns a user-friendly string representation of a value), then load
the string (load
returns a value or block of values by reading and evaluating a source)
>> b: [1 [2 3] [4 [5 6] 7]]
>> form b
== "1 2 3 4 5 6 7"
>> load form b
== [1 2 3 4 5 6 7]
>> b: [a b [c d [e f [g]]]]
== [a b [c d [e f [g]]]]
>> form b
== "a b c d e f g"
>> load form b
== [a b c d e f g]
collect
and keep
collect
's help page shows the following:
USAGE:
COLLECT body
DESCRIPTION:
Collect in a new block all the values passed to KEEP function from the body block.
COLLECT is a function! value.
ARGUMENTS:
body [block!] "Block to evaluate."
REFINEMENTS:
/into => Insert into a buffer instead (returns position after insert).
collected [series!] "The buffer series (modified)."
basically, collect
takes all values passed to keep
within its argument block and returns a series with those return values.
Effectively, it works as a way in which you can apply any block of code to a series and collect results from it.
You can use it as a map:
collect[foreach i arr[keep i + 1]]
(increments each array element)
a filter:
collect[foreach i arr [if i < 2 [keep i]]]
(keeps all array elements less than 2)
and much more. It finds use in any general place where you need to gather values for a code golf question. I have used it in this answer as a flatmap, for example.
Another non-universal alternative to type conversion is to use some arithmetic operation on the identity value (in the desired type) for the operation and the value to convert:
integer!
to float!
:
>> to-float 5
== 5.0
>> to 0.0 5
== 5.0
>> 0.0 + 5
== 5.0
char!
to integer!
:
>> to-integer #"A"
== 65
>> to 0 #"A"
== 65
>> 0 +#"A"
== 65
integer!
to pair!
(a pair with equal x
and y
values)
>> as-pair 5 5
== 5x5
>> to-pair[5 5]
== 5x5
>> as-pair 5 5
== 5x5
>> to 1x1 5
== 5x5
>> 1x1 * 5
== 5x5
integer!
to tuple!
(a tuple with all parts equal)
>> to-tuple[255 255 255]
== 255.255.255
>> to 0.0.0[255 255 255]
== 255.255.255
>> 0.0.0 + 255
== 255.255.255
integer!
or float!
to percent!
:
>> to-percent 12
== 1200%
>> to 1% 12
== 1200%
>> 0%+ 12
== 1200%
any
to provide a default valueSome functions (find
, select
and so on) could return none
. The long way to structure your code around their result is to use conditionals - if
, either
etc.
Let's find the number of occurences of each character in the string "Tips for golfing in Red". h
is a map!
that wiil hold the frequencies.
The verbose way is to use either key[true-code][false-code]
- if the key
exists do true-code
, otherwise do false-code
:
h: #()
s: "Tips for golfing in Red"
foreach c s[h/:c: 1 + either k: h/:c[k][0]]
h
== #(
#"T" 1
#"i" 3
#"p" 1
#"s" 1
#" " 4
#"f" 2
#"o...
We can achieve the same result with any
- it evaluates and returns the first truthy value. The first value in the block is the value we want to test for existence, the seconf one - the default value. So, if the key doesn'r exist, any
will return the default value:
h: #()
s: "Tips for golfing in Red"
foreach c s[h/:c: 1 + any[h/:c 0]]
h
== #(
#"T" 1
#"i" 3
#"p" 1
#"s" 1
#" " 4
#"f" 2
#"o...
alter
instead of append/insertSometimes it is certain that the value we are appending to a list, is not aleady present. In such case we can use alter
instead of append
for 1 byte less.
alter
appends a value if it's not found in the series, otherwise, removes it from the series.
>> b: [1 2 3 4 5]
== [1 2 3 4 5]
>> alter b 6
== true
>> b
== [1 2 3 4 5 6]
forall
instead of foreach
If you reference the current value of the series only once, you can save a byte by using forall
instead of foreach
:
>> p: [3 1 4 1 5 9 2]
== [3 1 4 1 5 9 2]
>> foreach n p[prin n]
3141592
>> forall p[prin p/1]
3141592
char!
values>> ? char!
null #"^@"
newline #"^/"
slash #"/"
escape #"^["
comma #","
lf #"^/"
cr #"^M"
space #" "
tab #"^-"
dot #"."
sp #" "
dbl-quote #"^""
sp
for space (#" "
or " "
), lf
for newline (#"^/"
or "^/"
), tab
(#"^-"
or "^-"
) etc. can save you a byte if enclosed in brackets or between strings:
either a/1 = i[1][" "]
either a/1 = i[1][sp]