7
\$\begingroup\$

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

Please post one tip per answer.

Lexurgy is a tool created by Graham Hill/def-gthill meant for conlangers (people who create constructed languages) to apply sound changes to their lexicon. As a result, Lexurgy is highly geared towards rule-based string operations. Its feature set includes capturing, character classes, and much more as detailed in the documentation below.

The documentation for Lexurgy is here, and a cheatsheet is here.

You can access Lexurgy here.

\$\endgroup\$

6 Answers 6

3
\$\begingroup\$

Reducing Whitespace

Lexurgy has specific rules about where whitespace can be removed. Consider the following rule (taken from my submission to Covfefify a string):

part-1:
 @consonant * => @consonant ; / $ @consonant* @vowel* _ // {$ _, $ @consonant _}

Lexurgy parses the rules as such, with <> separating individual elements:

<part-1>:
 <@consonant *> => <@consonant ;> / <$ @consonant* @vowel* _> // <{<$ _>, <$ @consonant _>}>

You cannot remove any whitespace within the <> or else it will yield a parsing error. As a result, with all extraneous whitespace removed, the rule turns into:

part-1:
@consonant *=>@consonant ;/$ @consonant* @vowel* _//{$ _,$ @consonant _}

If both sides have only 1 possible string on each side, then you can combine them:

# single string
a:
s t r=>o t h

b: # -1 byte per space
str=>oth

# combinable strings
c:
s t r *=>* o t h

d: # -1 byte per space
str *=>* oth

# two or more strings
e:
str ing=>oth er

f: # -1 byte per string
string=>other
\$\endgroup\$
2
\$\begingroup\$

Caveats about Lexurgy

  • Lexurgy treats whitespace in the input as word separators, so whitespace must be replaced by some other character. Individual inputs are separated by newlines, and those cannot be escaped in the input box.
  • Escaping certain characters is done with \, i.e. \! => !.
  • Lexurgy is designed for working on characters from a set of characters; use [] for matching any single character.
\$\endgroup\$
1
\$\begingroup\$

Use class variables within class declarations

Lexurgy allows you to define arbitrary "classes" of characters which can be accessed by @classname. Classes must have at least 1 character within them. Consider the following classes:

# 75 bytes
Class v {a,e,i,o,u}
Class c {p,t,k,b,d,g}
Class l {a,e,i,o,u,p,t,k,b,d,g}

# 59 bytes (-16 bytes)
Class v {a,e,i,o,u}
Class c {p,t,k,b,d,g}
Class l {@v,@c}

A class is minimum 11 bytes long (Class n {c} to account for the single character needed for a class), and each additional character is +2 bytes. Consider these two minimum classes, and wanting to make a class c that is the union of a and b:

Class a {a}
Class b {b}

Class c {a,b}   # +13 bytes
Class c {@a,@b} # +15 bytes

For minimal classes it's better to use the explicit declaration instead of using class variables.

The break-even point is at three characters for 2 classes:

Class a {a,e}
Class b {b}

Class c {a,b,e} # +15 bytes
Class c {@a,@b} # +15 bytes

Let there be \$c \ge 2\$ classes. The total number of characters \$n\$ in classes will cause the byte count to break even (i.e. using class variables is just as good as explicitly declaring the union) at \$2n=3c \Rightarrow n=\frac{3}{2}c\$.

Therefore, it is better to use variables when \$n \ge \frac{3}{2}c\$, and explicit declarations when \$n \le \frac{3}{2}c\$.

(Desmos link to my calculations)

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

Programs with no input

Programs with no input are possible in Lexurgy, with a rule like:

# +7 bytes
a:
*=>c

It takes an empty string and outputs a character for you to further mutate as needed. You can put an entire string on the right-hand side as well.

This must be the first rule for anything useful to happen.

However, if the program is given input, it will apply the rule to each input and every possible match in the input strings.

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

Use classes as variables holding strings

You can place entire, arbitrary strings into class definitions, provided they are properly escaped:

Class s {Hello\,\ world\!}

Then, use it like any other class:

# 38 bytes
a:
[]=>Hello\,\world\!Hello\,\world\!

# 41 bytes
Class s {Hello\,\ world\!}
a:
[]=>@s @s

The above example gains a 3 bytes, but if you use the string multiple times you get even more savings:

# 53 bytes
a:
[]=>Hello\,\world\!Hello\,\world\!Hello\,\world\!

# 44 bytes
Class s {Hello\,\ world\!}
a:
[]=>@s @s @s
\$\endgroup\$
0
\$\begingroup\$

The "Find/Marker/Delete" Pattern

A common pattern that I've found, which I've named the "Find/Marker/Delete" pattern, shows up often whenever the output is unrelated to the input except for some value that cannot be done using a simple replacement.

For example, consider this code that will output true or false if the word ends with e:

a:
*=>|true/e _ $
else:
*=>|false/_ $
b propagate:
[]=>*/_ |
c:
|=>*

This code has three parts:

# part a: find and place the marker. (here it's a |)
a:
*=>|true/e _ $
else:
*=>|false/e _ $
# part b: delete everything before/after the marker. (here it's everything before)
b propagate:
[]=>*/_ |
# part c: delete the marker
c:
|=>*

This pattern is the only real way you can have an output that is not some simple replacement of the input.

The minimal version for 2 outputs is as such (68 bytes):

a:
*=>|a/e _ $
else:
*=>|b/_ $
b propagate:
[]=>*/_ |
c:
|=>*
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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