Infinitely many term expansions are unexpectedly defined
Motivated by what @rodrigosetti said in https://github.com/mthom/scryer-prolog/discussions/2450#discussioncomment-10076075, I looked again at https://github.com/mthom/scryer-prolog/issues/987#issuecomment-858886019 which mentions:
The term expansion rules of dcgs are loaded during bootstrapping ...
So I asked Scryer: Which term expansions are currently defined?
?- term_expansion(T, E). T = (:-op(_A,_B,[_C])), E = [(:-op(_A,_B,_C))] ; T = (:-op(_A,_B,[_C,_D])), E = [(:-op(_A,_B,_C)),(:-op(_A,_B,_D))] ; T = (:-op(_A,_B,[_C,_D,_E])), E = [(:-op(_A,_B,_C)),(:-op(_A,_B,_D)),(:-op(_A,_B,_E))] ; T = (:-op(_A,_B,[_C,_D,_E,_F])), E = [(:-op(_A,_B,_C)),(:-op(_A,_B,_D)),(:-op(_A,_B,_E)),(:-op(_A,_B,_F))] ; ... .
That's of course not the "correct" way to query this predicate so that it answers the above question. But still: The result is unexpected! And further:
?- term_expansion(T, E), false. loops, unexpected. false. % expected
And further: Even if such expansions are loaded during bootstrapping, what exactly prevents their elimination at the end of bootstrapping? After bootstrapping is completed, I would expect a freshly generated Prolog system where no term expansions are (yet) defined.
Currently, I get:
?- term_expansion(T, E). error(instantiation_error,throw/1).
This seems reasonable I think? Certainly better than nontermination.
There is a common pattern I observe in expansions:
term_expansion(A, B) :-
nonvar(A),
% Actual expansion code
.
And I don't know if it should or shouldn't be used. Usage of this patern greatly influence output of your query.
I started to think that Prolog runtime should take more control and not blindly execute user provided expansions. What do you think about predicate ´term_expansion_rule/2´, where second argument isn't the result of term expansion, but a list of clauses that upon execution will expand first argument? Then it will be possible to enumarate all (even missbehaving) term expansions.
Regarding the test: I think a nonvar/1 test should not be necessary, since expand_term/2 should call term_expansion/2 only for non-variable terms? At least that's how GNU Prolog documents it:
http://www.gprolog.org/manual/gprolog.html#expand-term%2F2