Your translation is a valid one. It does not influence steadfastness. However, it still might not be very desirable. But this depends on the precise implementation you employ. Consider:
opcl --> "".
opcl --> "(", opcl, ")".
With Prolog flag double_quotes
set to chars
, the second clause now might be expanded to
opcl1(['('|S0],S) :-
opcl1(S0,S1),
S1 = [')'|S].
or
opcl2(['('|S0],S) :-
opcl2(S0,[')'|S]).
Now consider the goal phrase(opcl,"(((())))"
.
On common machines like WAM (e.g. YAP, SICStus), ZIP (SWI), TOAM Jr. (B):
opcl1
opcl1
will simply test the validity of the list, using the call-stack for the procedural control. On success, no cons-cell will have been created, and the call-stack will be empty again. Actually, above implementations are not able to detect that the goal is determinate, so they will leave one choice-point open. You can see this on the toplevel:
?- phrase(opcl,"(((())))").
true
; false.
This choice-point can be cleanly and safely removed with call_semidet/1
.
opcl2
opcl2
will create four instances of [')'|_] on the heap that need to be reclaimed by GC. But they are saving the call-stack. That is, there will be only tail-recursive calls which are very efficiently handled on WAM, minimally less efficiently on TOAM Jr. and relatively costly on SWI.
Things become even more costly when we are considering execution with occurs-check. In Qu-Prolog it is always on, and in SWI, XSB, and CX you can enable it with a flag like so:
?- phrase(opcl,Xs,Xs).
true
; Xs = ['(',')'|Xs]
; Xs = ['(','(',')',')'|Xs]
; ... .
?- set_prolog_flag(occurs_check,true).
true.
?- phrase(opcl,Xs,Xs).
true
; loops.
SWI does not need to perform a single occurs-check for opcl1
. But it does so for each )
in opcl2
.
So for these machines, your translation does not appear favorable. But it might be of interest for another machine, where there is no separate call-stack and which is not based on continuations.
call//1
Your translation will change the precise connection within call//1
. However, the goal within call//1
must always be written in a manner such that it is steadfast! Otherwise, the difference could be seen already when calling phrase(call(Cont),Xs0,Xs)
! For a conforming Cont
this will be the same as phrase(call(Cont),Xs0,XsC), XsC=Xs
As to your quote about steadfastness: It is a very informal definition of the notion. After all, what means "wrongly"?
The best definition of steadfastness for phrase/3
so far, I am aware of is:
phrase(NT, Xs0,Xs)
and phrase(NT, Xs0, XsC), XsC = Xs
with XsC
a fresh new variable, are always the same.