列表替换中的 Prolog 元素

Posted

技术标签:

【中文标题】列表替换中的 Prolog 元素【英文标题】:Prolog element in lists replacement 【发布时间】:2011-08-16 14:16:27 【问题描述】:

你好,我想知道你是否可以帮我解决这个问题

来自 Prolog 中的编程:编写 Prolog 脚本以将列表中的任何给定元素替换为另一个给定元素。例如:

replace( 3, a,[1,2,3,4,3,5], [1,2,a,4,a,5])=true

提前致谢

【问题讨论】:

我还没试过,我不知道该怎么做。 【参考方案1】:

在 Prolog 中,大多数列表处理是通过处理头部然后递归处理列表的其余部分来完成的。当然,你不能忘记基本情况,它是一个空列表。

将任何内容替换为空列表中的任何内容都会再次生成一个空列表。如果列表的头部与要替换的元素相同,则替换它,否则保持原样。在这两种情况下,递归处理列表的其余部分。从英文翻译成Prolog:

replace(_, _, [], []).
replace(O, R, [O|T], [R|T2]) :- replace(O, R, T, T2).
replace(O, R, [H|T], [H|T2]) :- H \= O, replace(O, R, T, T2).

【讨论】:

【参考方案2】:
replace(_, _ , [], []).

replace(X, Y, [ X | Z ], [ Y | ZZ]):- ! , replace( X, Y, Z, ZZ).

replace(X, Y, [ W | Z], [ W | ZZ] :- replace(X, Y, Z, ZZ). 

不过,通常会将 3.arg 安排为第一个。严格来说,上面并没有替换列表中的任何内容,它只是回答第 4 个参数是否与第 3 个参数相同,但使用 Y' 而不是 X'。

【讨论】:

【参考方案3】:
replace(E,S,[],[]).
replace(E,S,[E|T1],[S|T2]):-replace(E,S,T1,T2).
replace(E,S,[H|T1],[H|T2]):-E\=H, replace(E,S,T1,T2).

思路很简单,如果元素匹配,就改变它,如果不匹配,就往前走,直到为空。

【讨论】:

【参考方案4】:
domains
I=integer*
K=integer*
Z=integer
A=integer
predicates
nondeterm  rep(I,Z,A,K)
clauses
rep([],_,_,[]).
rep([Z|T1],Z,A,[A|T2]):- rep(T1,Z,A,T2).
rep([H|T1],Z,A,[H|T2]) :- rep(T1,Z,A,T2).
goal
rep([1,2,3],2,4,X).

【讨论】:

【参考方案5】:

到目前为止,在其他答案中提出的所有实现在与非基本术语一起使用时逻辑上不合理。考虑原始查询和一个轻微的变体:

?- replace(3,three,[1,2,3],Xs).
Xs = [1,2,three] ;                 % OK: correct
false

?- A=3, replace(A,B,[1,2,3],Xs).   % OK: correct
Xs = [1,2,B], A = 3 ;
false

有效!让我们问一些非常相似的问题:

?- replace(A,B,[1,2,3],Xs).        % FAIL: should succeed more than once...
Xs = [B,2,3], A = 1 ;              %       ... but the other solutions are missing 
false

?- replace(A,B,[1,2,3],Xs), A=3.   % FAIL: this query _should_ succeed ...
false                              %       ... it does not!

发生了什么事?责备元逻辑内建(!)/0(\=)/2非常很难正确使用,并且经常使代码脆弱、不纯且逻辑不健全。

为了保持逻辑合理性坚持逻辑纯洁并尽可能避免使用元逻辑“特征”!幸运的是,大多数 Prolog 实现都支持dif/2 作为(\=)/2 的逻辑替代方案。让我们使用它:

% code by @svick, modified to use dif/2 instead of (\=)/2
replaceP(_, _, [], []).
replaceP(O, R, [O|T], [R|T2]) :- replaceP(O, R, T, T2).
replaceP(O, R, [H|T], [H|T2]) :- dif(H,O), replaceP(O, R, T, T2).

让我们再次运行上面的查询,这次使用改进后的replaceP/4

?- replaceP(3,three,[1,2,3],Xs).
Xs = [1,2,three] ;                 % OK: correct, like before
false

?- replaceP(A,B,[1,2,3],Xs).       % OK: four solutions, not just one
Xs = [B,2,3], A = 1 ;         
Xs = [1,B,3], A = 2 ;
Xs = [1,2,B], A = 3 ;
Xs = [1,2,3], dif(A,1),dif(A,2),dif(A,3) ;
false

?- replaceP(A,B,[1,2,3],Xs), A=3.  % OK (succeeds now)
Xs = [1,2,B], A = 3 ;                 
false
?- A=3, replaceP(A,B,[1,2,3],Xs).  % OK (same as before)
Xs = [1,2,B], A = 3 ;
false

【讨论】:

以上是关于列表替换中的 Prolog 元素的主要内容,如果未能解决你的问题,请参考以下文章

Prolog中的列表练习列表

如何通过Prolog将字符串连接到列表中的多个元素?

尝试使用prolog将变量分配/提取到列表列表中的不同元素

Prolog 中的前缀

Prolog 中的子列表谓词

使用Prolog规则在查询中显示给定列表的第一个元素?