所以我有一个程序,它有一个谓词用一个给定的新元素替换列表中某个元素的第一个出现并生成一个新列表。我这样做了:
changeFst(OldE,[OldE|T],NewE,[NewE|T]):-!.
changeFst(OldE,[_|T],NewE,_):- changeFst(OldE,T,NewE,_),!.
例如,如果你给(2,[1,2,3,4,2],10,X)它应该给你回来 X = [1,10,3 ,4,2]
现在我正在制作更改最后一次出现的部分(在示例中它将返回 X = [1,2,3,4,10])。这里是我的代码:
changeLast(OldE,OldL,NewE,NewL):-
reverse(OldE,X),
changeFst(OldE,X,NewE,NewL),
!.
所以这实际上是完美的,但事情是它返回我反转的列表(在我上面的例子中它返回我 [10,4,3,2,1] 而不是 [1,2,3,4,10] )
如何才能再次将其反转以正确显示我的答案?
答案 0 :(得分:3)
changeFst/4
的定义在许多方面都不正确,例如changeFst(o,[o,o],n,[m,y,s,t,e,r,y]).
成功,但显然它应该失败。原因是你不正确使用削减。如果你想学习Prolog,首先要坚持纯粹的声明性子集。这意味着没有削减,也没有副作用。
所以这里的定义不依赖于削减:
changeFst(Old,[Old|Olds],New,[New|Olds]).
changeFst(Old,[E|Olds],New,[E|News]):-
dif(Old, E),
changeFst(Old,Olds,New,News).
这种纯粹关系的一个优点是我们可以使用最通用的查询来查看我们得到的答案:
| ?- changeFst(Old, Olds, New, News).
Olds = [Old|_A],
News = [New|_A] ? ;
Olds = [_A,Old|_B],
News = [_A,New|_B],
prolog:dif(Old,_A) ? ;
Olds = [_A,_B,Old|_C],
News = [_A,_B,New|_C],
prolog:dif(Old,_A),
prolog:dif(Old,_B) ? ;
Olds = [_A,_B,_C,Old|_D],
News = [_A,_B,_C,New|_D],
prolog:dif(Old,_A),
prolog:dif(Old,_B),
prolog:dif(Old,_C) ? ...
您是否注意到答案始终包含Olds
部分列表?喜欢:
第一个答案中Olds = [Old|_A]
。这可能有点过于笼统,毕竟这意味着现在甚至接受非名单:
| ?- changeFst(o,[o|nonlist], New, News).
News = [New|nonlist] ?
yes
因此,您可能希望确保Olds
和News
始终是列表。
但是我要表明这一点,而是告诉你,只要有一种纯粹的关系,你就会看到许多东西,这些东西是一个切割不前的程序永远无法直接向你展示的。
如果我们在这:它如何处理空列表?当前版本表明changeFst/4
应该失败。不知道你想要什么,但如果你想让它成功,先添加一个事实changeFst(_,[],_,[]).
。
如果您的Prolog不支持dif/2
(this answer)的定义,请参阅prolog-dif。
答案 1 :(得分:1)
@false建议使用if_/3
和(=)/3
一起保持纯粹和高效:
<div id="header" role="banner">
<div id="headerimg">
<h1><a href="http://balit.ir/blog/">Mohammad Kermani</a></h1>
<div class="description"></div>
</div>
</div>
<hr />
示例查询:
changeFst(Old,Olds,New,News) :-
list_change_first_(Olds,News,Old,New).
list_change_first_([],[],_,_).
list_change_first_([X|Xs],[Y|Ys],Old,New) :-
if_(X = Old, (Y = New, Ys = Xs),
(Y = X, list_change_first_(Xs,Ys,Old,New))).