【问题标题】:Prolog - replacing list elementsProlog - 替换列表元素
【发布时间】:2014-06-29 22:31:00
【问题描述】:

所以我有一个程序,它有一个谓词,用给定的新元素替换列表中某个元素的第一次出现并生成一个新列表。我已经这样做了:

    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(o,[o,o],n,[o,n]).成功了,但是根据你的描述应该失败了!
  • 即使changeFst(o,[o,o],n,[]). 成功了,显然应该失败。

标签: list prolog element last-occurrence


【解决方案1】:

您对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

因此,您可能希望确保 OldsNews 始终是列表。

但我要说明这一点的目的是向您展示,通过纯粹的关系,您会看到很多东西,一个受过干扰的程序永远无法直接向您展示。

如果我们这样做:如何处理空列表?当前版本建议 changeFst/4 应该失败。不确定你想要什么,但如果你想让它成功,请先添加一个事实changeFst(_,[],_,[]).

如果您的 Prolog 不支持 dif/2 () 的定义,请参阅 this answer

【讨论】:

    【解决方案2】:

    按照@false 的建议,将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...
    

    【讨论】:

    • % and so on... 你没有更好的名字吗。理想情况下,prolog-toplevel 可以使用这样的约定来表示查询已停止。我考虑过...,但不是 100% 确定。
    • @false。如何使用 SO 按键标记?我见过你偶尔使用它们...关于如何永久使用它们的建议?例如,“钥匙;” vs "key enter" vs 没有按下任何键但引发异常。
    • 理想情况下它应该是有效的 Prolog 语法,ASCII 并由顶层打印
    猜你喜欢
    • 2011-08-16
    • 1970-01-01
    • 2013-03-21
    • 2016-03-28
    • 1970-01-01
    • 2018-04-15
    • 1970-01-01
    • 2015-01-08
    • 1970-01-01
    相关资源
    最近更新 更多