3

So I have a program that has a predicate to replace the first occurrence of some element of a list with a given new element and produce a new list. I have it done like so:

    changeFst(OldE,[OldE|T],NewE,[NewE|T]):-!.
    changeFst(OldE,[_|T],NewE,_):- changeFst(OldE,T,NewE,_),!.

For example if you give (2,[1,2,3,4,2],10,X) it should give you back X=[1,10,3,4,2]

now im making the part that changes the last occurrence (in the example it would return X=[1,2,3,4,10]). Here's my code:

    changeLast(OldE,OldL,NewE,NewL):-
       reverse(OldE,X), 
       changeFst(OldE,X,NewE,NewL),
       !.

so this works in fact perfectly but the thing is it returns me the list reversed ( in my upper example it returns me [10,4,3,2,1] instead of [1,2,3,4,10])

How can I just reverse this again to get my answer properly displayed?

4

2 回答 2

4

您的定义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

于 2014-06-29T23:06:11.867 回答
1

按照@false 的建议,通过if_/3与 with 一起使用,保持纯粹和高效:(=)/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...
于 2015-06-16T03:46:33.347 回答