3

I am trying to dig into the GNU Prolog behaviour of:

test(X,I,O) :- phrase(X,I,O).
?- test(("a",!,"b"),"ab","").

Is there a standard way to see to what phrase/3 translates?

According to the ISO DCG proposal (*), there is the requirement that we will have an expand_term/2. Now I can use this to check:

?- expand_term((foo --> "a", !, "b"),X).
X = (foo([97|A],B):-!,A=[98|B])

Does this tell me how phrase/3 is used in my test/3?

(*) ISO/IEC DTR 13211–3:2006
Definite clause grammar rules
Klaus Daessler
November 20, 2012
http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dcgs/dcgsdin121120.pdf

2 Answers2

3

Is there a standard way to see the what phrase/3 translates?

No. The meaning of phrase/3 is defined, but the actual implementation behind is not accessible. There are several different ways, how phrase/3 can be defined. It could be as simple as in YAP:

phrase(P, S0, S) :-
        call(P, S0, S).

Or it could use expand_term/2 (or something of that kind). That is:

phrase(P, S0, S) :-
   expand_term(( pseudont --> P ), ( pseudont(CS0, CS) :- Goal) )),
   S0 = CS0,
   S = CS,
   Goal.

It could execute the final unification after calling Goal:

phrase(P, S0, S) :-
   expand_term(( pseudont --> P ), ( pseudont(CS0, CS) :- Goal) )),
   S0 = CS0,
   Goal,
   S = CS.

And by that introduce the (implementation dependent) convention that the expanded predicates are always called with an uninstantiated and unaliased variable in the last argument which would permit tail-recursiveness in the presence of semicontext.

It is all up to the implementer.

Does this tell me how phrase/3 is used in my test/3?

No, there is no way telling.

But then, why do you ask? Or, to rephrase:

What effect could a differing but conforming implementation of phrase/3 have?

Resource consumption

This should be evident. Consider ?- phrase([],Xs). which does not create any term on the heap in YAP, but does so for the naive expand_term-expansion above. But then, resource consumption is out of scope of the current standards.

Variable ordering

Consider the body of a rule ..., phrase([], Xs, Xs), ... in YAP: Xs remains a local variable, whereas an expand_term-based phrase makes it global. In many implementations this would affect the relative order of variables. Now, the standard explicitly states in 7.2.1:

If X and Y are variables which are not identical then
X term_precedes Y shall be implementation dependent
except that during the creation of a sorted list (7.1.6.5,
8.10.3.1 j) the ordering shall remain constant.

So this is again not a problem, but still this might be annoying.

NSTO property

The Prolog standard (that is, part 1 ISO/IEC 13211-1) only defines execution if it is NSTO. That is, if all unifications happening during execution are NSTO — Not subject to occurs-check (see 7.3.3).

Now, consider your case: phrase(("a",!,"b"), Xs, Ys). At first sight, this is equivalent to phrase("ab", Xs, Ys). But now consider assuming set_prolog_flag(double_quotes,chars)

?- Xs = [c|_], Xs = Ys, phrase(("a",!,"b"), Xs, Ys).

This query should fail, no doubt. But is it NSTO? Naively, we could assume that this can be replaced by:

?- Xs = [c|_], Xs = Ys, Xs = [a,b|Ys].

Which is tantamount to:

?- Xs = [c|_], Xs = [a,b|Xs].

Clearly, Xs = [a,b|Xs] alone is STO (Subject to occurs check). But also both together are STO! To understand this, consider the Herbrand algorithm in 7.3.2. In essence, it non-deterministically rewrites the equations "in any order". Here is one such derivation:

          Xs = [c|Zs], Xs = [a,b|Xs].
(7.3.2 f) Xs = [c|Zs], [c|Zs] = [a,b,c|Zs].
(7.3.2 d) Xs = [c|Zs], c = a, Zs = [b,c|Zs].
(7.3.2 g) failure (not unifiable, positive occurs-check)

Of course, this derivation is unusual. Usually, one would fail immediately in the presence of c = a, but the algorithm is non-deterministic in this respect. And a set of equations is NSTO only if all possible derivations do not lead to 7.3.2 g. To cite 7.3.3:

A set of equations (or two terms) is "not subject to
occurs-check" (NSTO) iff there exists no way to proceed
through the steps of the Herbrand Algorithm such that
7.3.2 g happens.

freeze/2 and when/2

These constructs might also be affected. While they are currently not covered by existing standard documents understanding potential impacts is still of relevance. Consider:

?- freeze(L, (X=1;X=2)), phrase(("a",!,"b"),L).
   L = [a,b], X = 1.

B, SICStus, SWI, YAP all produce this one answer. So the cut is significant.


In any case, thanks for asking – I understood the NSTO issue only while answering your question! This clearly has some impact in how the DCG translation is formulated.

false
  • 10,264
  • 13
  • 101
  • 209
1

Since the ISO DCG does not define a way to figure out what phrase/3 is using as an executed term, the only way to figure it out, is to consult the source code. It is found here:

http://sourceforge.net/projects/gprolog/

The phrase/3 predicate is defined in a file called expand.pl. Its definition uses '$dcg_trans_body'/4. We can check it:

GNU Prolog 1.4.2
By Daniel Diaz
Copyright (C) 1999-2012 Daniel Diaz
| ?- '$dcg_trans_body'(("a",!,"b"), In, Out1, Body).

Body = (!,A=[98|Out1])
In = [97|A]

So the first terminal is indeed merged into the In parameter, similar as in the foo rule. Since this is done when phrase/3 is invoked, it shouldn't be a problem.