scryer-prolog
scryer-prolog copied to clipboard
Goal expansion for arguments of (',')//2
In my application, I define a goal expansion to replace every invocation of a//0 by that of b//0. For instance, consider the following definitions:
:- use_module(library(dcgs)). user:goal_expansion(a(Cs0,Cs), b(Cs0,Cs)). :- dynamic(p/2). :- meta_predicate(g(2,?,?)). p --> a. p --> g(a). p --> g(g(a)). p --> g((g(a),[])).
Yielding:
?- clause(p(Cs0, Cs), Body). Body = b(Cs0,Cs) ; Body = g(user:b,Cs0,Cs) ; Body = g(user:g(user:b),Cs0,Cs) ; Body = g(user:(g(a),[]),Cs0,Cs), unexpected.
The first 3 answers work completely as expected, with b appearing instead of a in Body. But in the last answer, g(a) appears unexpectedly, where we would expect g(b).
Analogously for (;)//2, i.e., if I write for example:
p --> g((a;[])).
I have filed #2367 for this, and it seems to address the issue. Is this change correct? Thank you a lot!
Very nice, I'd just started to look at this.
Unfortunately, #2367 in fact did not solve the issue. But, strangely, when I add the very same meta_predicate/1 declaration to the program itself, then it works as expected:
:- use_module(library(dcgs)).
:- meta_predicate(','(2, 2, ?, ?)).
user:goal_expansion(a(Cs0,Cs), b(Cs0,Cs)).
:- dynamic(p/2).
:- meta_predicate(g(2,?,?)).
p --> a.
p --> g(a).
p --> g(g(a)).
p --> g((g(a),[])).
yielding:
?- clause(p(Cs0, Cs), Body). Body = b(Cs0,Cs) ; Body = g(user:b,Cs0,Cs) ; Body = g(user:g(user:b),Cs0,Cs) ; Body = g(user:(user:g(user:b),user:[]),Cs0,Cs).
How does a/0 become b/0 when the goal expansion is a/2 to b/2? SWI-Prolog does this but Yap leaves a/0 as-is.
EDIT: never mind, ignore this. The '2' specifies extra closure arguments that must be taken into account and that makes it equivalent to a/2.
This happens because meta-predicate definitions are hidden behind modules. The user module is global but all other modules, including dcgs, are local, so they don't inform goal expansion at the level of the user module. Of course, once predicates are exported, (e.g. for phrase/{2,3,4,5}) their local meta-predicate definitions are exported too.
Interestingly, there is a fundamentally different way to go about implementing DCGs that I think would solve this specific issue: library(dcgs) could define and export predicates (',')/4, (->)/4 etc. This is the approach used by Yap:
https://github.com/vscosta/yap-6.3/blob/master/pl/grammar.yap#L28
With these Prolog predicates that directly correspond to grammar control constructs, phrase/N for compound goals can be implemented as a direct call:
https://github.com/vscosta/yap-6.3/blob/2e6528994219055d05394e64726b4bf6835104a3/pl/grammar.yap#L251
This implementation approach could be worth considering also for Scryer, especially if someone is interested in working on this and wants to compare the advantages of each variant.