Tips for golfing in Brachylog

19

4

Brachylog is a language that's beginning to rise in prominence in code-golfing recently (and just received a major update with a terser syntax). Like Prolog, it has the advantage that it can often solve a problem (typically via brute force) merely from a sufficiently accurate description of what a problem looks like, a feature that means that on the right sort of challenge, it's often comparable to the top golfing languages (and has been known to beat Jelly from time to time).

What tips do you have for golfing (i.e. writing the shortest possible programs in) Brachylog? This is mostly looking for advice that's specific to Brachylog in particular, rather than advice that's applicable to a wide range of languages. (Tips about golfing in declarative languages in general might potentially be appropriate here, depending on how much application they'll have to languages other than Brachylog, although see also Tips for golfing in Prolog.)

user62131

Posted 2017-01-26T20:25:52.323

Reputation:

Answers

4

Exploit nested predicates to create new variables

Brachylog has lots of special syntax cases to make its two special variables, ? (input / left parameter) and . (output / right parameter), terser to use. This means that if you don't need to access your predicate's ? and ., but do need to use variables, you can often save bytes via creating a nested predicate to use its ? and ..

As a simple example, consider a program that looks like this:

… A … ∧A … B … B …

This is a pretty common shape for a longer program; after all, there are lots of gaps that could contain anything. Suppose we have no need for ? or . inside the centre three gaps. Then we could rewrite it like this:

… { … & … . … } …

Here, the nested predicate's ? is serving the role of A, and its . is serving the role of B. We can observe that this is a byte shorter than the original code; changing AABB to {?.} has no change in terms of bytes, but this allowed us to simplify ∧? to the abbreviation &.

A related trick is to change

∧. … ?∧

to

~{ … }

(which is one byte shorter), although note that it's nearly always cheaper to get the caller to exchange the arguments instead (unless the predicate is called from at least three different places in the program, which is rare in Brachylog).

user62131

Posted 2017-01-26T20:25:52.323

Reputation:

3

Split up length-2 predicates inside metapredicates

This is best explained by example. To remove the first and last elements of a list, we behead and knife it:

bk

If we wanted to perform this operation on every element of a list, we can use a map operation:

{bk}ᵐ

However, it's a byte shorter to split the predicate into two, and map each part separately:

bᵐkᵐ

The same trick can be used with quite a few metapredicates:

{bk}ᵐ  →  bᵐkᵐ
{bk}ˢ  →  bˢkˢ
{bk}ᶠ  →  bᶠkˢ
~{bk}  →  ~k~b

Note that for some metapredicates, like , there's no general-purpose way to split it into two parts, but it may nonetheless be possible to find a decomposition that works for the specific task you're working on.

user62131

Posted 2017-01-26T20:25:52.323

Reputation:

3

Casting the empty list to the empty string

Sometimes, when working with strings, the algorithm we use might unify what we want with the empty list [], when we would rather want the empty string "".

We can cast the empty list to the empty string using ,Ẹ, which appends the empty string to its left variable (this is an exploit of the way , is implemented).

This also has the benefit that it does not do anything if the left variable is a string. So, if your program is

{  
   some predicate that should always output a string, 
   but actually outputs [] instead of "" in specific cases
}

Then

{
  some predicate that should always output a string, 
  but actually outputs [] instead of "" in specific cases
},Ẹ

will work the way you want.

Fatalize

Posted 2017-01-26T20:25:52.323

Reputation: 32 976

2

Single-element runs in a list

Consider this snippet:

ḅ∋≠

If the input is a list or string, the output is unified with a sublist/substring of length 1 that's not part of a longer run of equal elements. It splits the list into blocks of equal elements and finds a block whose elements are all different. To get the elements themselves instead of singleton lists, tack h to the end. I used this construct here with o to find a character that occurs only once in the input string.

Zgarb

Posted 2017-01-26T20:25:52.323

Reputation: 39 083