Why are empty productions of DCG grammars translated so that unifications occur in the body?

I’ve been trying to learn more about DCGs, and, while looking at the blanks predicate from the library dcg/basics, I noticed that what corresponds to the DCG rule blanks --> []. is translated into blanks(A, B) :- A=B.. My question was this: would it not be simpler to move the unification into the rule head and instead translate the DCG rule into blanks(A, A).? I really want to grok DCGs, so I would appreciate any pointers you all could provide.

?- use_module(library(dcg/basics)).
true.

?- listing(blanks).
dcg_basics:blanks(A, B) :-
    blank(A, C),
    !,
    D=C,
    blanks(D, B).
dcg_basics:blanks(A, B) :-
    A=B.

true.

For reference, the following is the output I get from running swipl --version: SWI-Prolog version 9.2.9 for arm64-darwin.

1 Like

Such additional polishing might be nice for us humans to see, but does not improve the meaning of the code.

When e.g. cuts are involved, the subtlety of the exact order that cuts vs unification attempts take effect is crucially important (because unification attempts are merely attempts and could fail), and the non-polished expansion correctly handles such subtlety :slightly_smiling_face:

1 Like

Old versions had this as a post-processing step in the DCG compiler. Recent versions do not because the compiler generates equally efficient code for the version with explicit unification.

3 Likes