Without the import, SWI-Prolog occasionally produced errors like: PROLOG SYSTEM ERROR: Thread 1 trapUndefined(): undefined: function_expansion:append/3 Explicitly importing the predicate solves the problem. I assume this has something to do with autoloading during term/goal expansion. That environment is somewhat fragile.
function_expansion can be used to expand mathematical constants in place. In that scenario, there's no need for a guard, so one should use =true= as the guard. There's no reason to include that guard in the macro expansion, so it's omitted. Other non-trivial guards are retained.
While documenting how function_expansion behaves, I wrote a small example and that example didn't work. The old code tried to expand double(X) which has a variable inside so ground/1 failed. I want nonvar/1 which allows for internal variables. Those internal variables will often be matched by the function_expansion rule. See ex below for an example.
This version correctly expands functions nested inside a goal. I need to clean up this code and see if there's a way to substantially simplify it. It seems like there must be. One place to start would be to create change_args(F, Term0, Term) which encapsulates this pattern: Term0 =.. [Functor|Args0], call(F, Args0, Args), Term =.. [Functor|Args], I use that pattern at least twice here.