aarroyoc / advent-of-code-2020

Solutions of Advent of Code 2020
The Unlicense
7 stars 0 forks source link

Using argument indexing for efficiency and generality #4

Closed triska closed 3 years ago

triska commented 3 years ago

I noticed the following snippet:

line(['*'|Cs]) --> "*",!,line(Cs).
line(['+'|Cs]) --> "+",!,line(Cs).
line(['('|Cs]) --> "(",!,line(Cs).
line([')'|Cs]) --> ")",!,line(Cs).
line(Cs) --> [C], { C = ' '}, line(Cs).

The main drawback is that the usage of !/0 restricts the generality of this code: We cannot use this grammar to generate all strings it describes.

On the other hand, if we leave everything as is, and only remove the occurrences of !/0, we suffer a performance drawback, because parsing will create and leave choice-points and therefore become less efficient.

One solution for this is to rewrite the code as follows:

line(Cs) --> [C], line_(C, Cs).

line_(*, [*|Cs])     --> line(Cs).
line_(+, [+|Cs])     --> line(Cs).
line_('(', ['('|Cs]) --> line(Cs).
line_(')', [')'|Cs]) --> line(Cs).
line_(' ', Cs)       --> line(Cs).

This extends the fragment's generality when generating strings, and benefits from first argument indexing to retain its efficiency when parsing.

Note that no single quotes are needed when writing the atoms * and +.

aarroyoc commented 3 years ago

Thank you so much! I've updated the code