以下代码是一个DCG,用于替换Find
和Replace
中所有Request
w / Result
的出现。把答案放在eos([], []).
replace(_, _) --> call(eos), !.
replace(Find, Replace), Replace -->
Find,
!,
replace(Find, Replace).
replace(Find, Replace), [C] -->
[C],
replace(Find, Replace).
substitute(Find, Replace, Request, Result):-
phrase(replace(Find, Replace), Request, Result).
。感谢mat,代码,this question。
replace(_, _, A, B) :-
call(eos, A, C), !,
B=C.
replace(A, D, B, F) :-
phrase(A, B, C), !,
E=C,
replace(A, D, E, G),
phrase(D, F, G).
replace(B, C, A, E) :-
A=[F|D],
replace(B, C, D, G),
E=[F|G].
substitute(A, B, C, D) :-
phrase(replace(A, B), C, D).
eos([], []).
在SWI-Prolog中,这扩展到以下内容。
phrase
这段代码是尾递归的吗?在谓词replace
的第二个定义中递归调用replace
后,调用E=[F|G]
。在replace
的第3个定义中递归调用replace
之后,还有{{1}}。我认为,如果最后进行递归调用,代码将是尾递归的。如果生成的代码不是尾递归的,有没有办法让Prolog生成尾递归代码?提前谢谢。
答案 0 :(得分:4)
上面的代码包含非常复杂的结构,例如半导体文本的非常广泛的泛化。请注意,上面Find
和Replace
都可以是一般的非终端 - 不仅仅是列表。
所以让我们考虑一个更简单的案例:
iseq([]) --> [].
iseq([E|Es]) --> iseq(Es), [E].
在许多Prolog中扩展为:
iseq([], Xs, Xs).
iseq([E|Es], Xs0,Xs) :-
iseq(Es, Xs0,Xs1),
Xs1 = [E|Xs].
这也不是尾递归,但可以通过交换两个目标来实现。 尽管如此,许多人认为上述翻译更为可取,因为它显然保留了某些理想的属性,并且还导致了更高效的执行。