Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Goal expansion for arguments of (',')//2 #2366

Open
triska opened this issue Mar 20, 2024 · 7 comments
Open

Goal expansion for arguments of (',')//2 #2366

triska opened this issue Mar 20, 2024 · 7 comments

Comments

@triska
Copy link
Contributor

triska commented Mar 20, 2024

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).

@triska
Copy link
Contributor Author

triska commented Mar 20, 2024

Analogously for (;)//2, i.e., if I write for example:

p --> g((a;[])).

@triska
Copy link
Contributor Author

triska commented Mar 21, 2024

I have filed #2367 for this, and it seems to address the issue. Is this change correct? Thank you a lot!

@mthom
Copy link
Owner

mthom commented Mar 21, 2024

Very nice, I'd just started to look at this.

@triska
Copy link
Contributor Author

triska commented Mar 28, 2024

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).

@infradig
Copy link

infradig commented Mar 31, 2024

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.

@mthom
Copy link
Owner

mthom commented Apr 1, 2024

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.

@triska
Copy link
Contributor Author

triska commented Apr 7, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants