所以我有一个程序,它有一个谓词,用给定的新元素替换列表中某些元素的第一次出现,并生成一个新列表。我是这样完成的:
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])
我怎样才能再次反转以正确显示我的答案?
您对
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], dif(Old,_A)
; Olds = [_A,_B,Old|_C], News = [_A,_B,New|_C],
dif(Old,_A), dif(Old,_B)
; Olds = [_A,_B,_C,Old|_D], News = [_A,_B,_C,New|_D],
dif(Old,_A), dif(Old,_B), dif(Old,_C)
; ... .
您是否注意到答案总是包含
Olds
部分列表?喜欢:
第一个答案中的Olds = [Old|_A]
。这可能有点太笼统了,毕竟这意味着现在甚至接受非列表:
?- changeFst(o,[o|nonlist], New, News).
News = [New|nonlist]
; false.
因此您可能需要确保
Olds
和 News
始终是列表。
但我要展示这一点的目的是向你展示,通过纯粹的关系,你可以看到很多东西,而一个被剪切的程序永远无法直接向你展示。
如果我们这样做:如何处理空列表?当前版本建议
changeFst/4
应该失败。不确定您在这里想要什么,但如果您希望成功,请先添加一个事实changeFst(_,[],_,[]).
。
如果您的 Prolog 不支持dif/2
(
prolog-dif),请参阅这个答案。
if_/3
与 (=)/3
一起使用,保持纯粹和高效:
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))).
示例查询:
?- changeFst(2,[1,2,3,4,2],10,Xs).
Xs = [1,10,3,4,2]. % succeeds deterministically
?- changeFst(o,[o,o],n,[m,y,s,t,e,r,y]).
false. % expected result
?- changeFst(Old,Olds,New,News).
Olds = [], News = [] ;
Olds = [Old|_A], News = [New|_A] ;
Olds = [_A], News = [_A], dif(_A,Old) ;
Olds = [_A,Old|_B], News = [_A,New|_B], dif(_A,Old) ;
Olds = [_A,_B], News = [_A,_B], dif(_A,Old), dif(_B,Old) ;
Olds = [_A,_B,Old|_C], News = [_A,_B,New|_C], dif(_A,Old), dif(_B,Old) % and so on...