【问题标题】:PROLOG defining 'delete' predicatePROLOG 定义“删除”谓词
【发布时间】:2016-11-13 07:40:43
【问题描述】:
delete(X,[X|R],[_|R]).
delete(X,[F|R],[F|S]) :-
    delete(X,R,S).

以上是我对删除谓词的定义,对于delete(X,L,R),意在删除L中所有出现的X,结果为R。

我在下面查询,得到“G2397797”。这个字符串代表什么?

?- delete(1,[1,2,3,4,5],X).
X = [_G2397797, 2, 3, 4, 5] .

【问题讨论】:

  • delete(X, [X|R], [_|R]). 不只是删除 X,而是用匿名变量 (_) 替换它。那是你真正想要的吗?

标签: prolog


【解决方案1】:

如果你只是更正你的第一个子句并删除不必要的匿名变量,你会得到:

delete_each(X, [X|L], L).
delete_each(X, [Y|Ys], [Y|Zs]) :-
        delete_each(X, Ys, Zs).

这将使用统一,并在回溯时删除列表中每个出现的 X:

?- delete_each(a, [a,b,a,c], R).
R = [b, a, c] ;
R = [a, b, c] ;
false.

你知道这与select/3 有何相同之处吗?

如果要删除列表中所有出现的 X,可以查看answer by @coder

【讨论】:

    【解决方案2】:

    在您得到X = [_G2397797, 2, 3, 4, 5] . 的答案中,_G2397797 不是字符串,而是未实例化的变量。这是由于子句:

    delete(X,[X|R],[_|R]).
    

    在输出列表中放置一个匿名变量“_”。你可以写delete(X,[X|R],R).

    但这有多个问题。首先,它只删除 first 出现的 X 而不是全部,因为在上面的子句中,当你找到一个你成功的时候。此外,您还没有想到空列表的情况,这也是递归的基本情况。最后,在您的第二个子句中,您没有应用任何说明 F 和 X 不同的规则,并且当 F 等于 X 时,该子句会给出错误的结果。

    所以你可以写:

    delete(_,[],[]).
    delete(X,[X|R],S):-delete(X,R,S).
    delete(X,[F|R],[F|S]):-dif(X,F),delete(R,S).
    

    【讨论】:

    • library delete/3 in SWI-Prolog 的文档中有一条非常有说服力的评论,至少:“已弃用:有太多方法可能希望从列表中删除元素来证明名称的合理性。考虑匹配(===),首先/全部删除,确定与否。”无论哪种方式,我认为 OP 的删除是为了与 = 匹配,首先,在回溯时删除下一个。
    • 我不太确定我是否完全理解。你的意思是这样的:删除(_,[],[])。删除(X,[Y|R],S):-(X=Y ->S=[X|T], 删除(X,R,T); 删除(X,R,S) )。
    • cmets 中的代码有点难;看我的回答
    • 谢谢鲍里斯!,我明白了。