【问题标题】:Prolog permutation predicate using insertion of elements使用元素插入的 Prolog 置换谓词
【发布时间】:2017-03-29 13:24:40
【问题描述】:

我正在尝试编写一个谓词permutation/2,这样当且仅当两个参数都是列表时,它才是真的,一个是另一个的排列。为此,我编写了两个辅助谓词delete/3insert/3。当且仅当第三个参数是第二个参数时,第一个为真,两个列表都删除了第一个参数中元素的第一个实例。当且仅当第三个参数等于插入了第一个参数(元素)的第二个参数时,第二个才是真的。

delete(X,[X|T],T). % Base case, element equals head.
delete(X,[A|B],[A|C]) :- delete(X,B,C). % Else, repeat for the tail.

insert(X,[],[X]). % Base case.
insert(X,[H|T],B) :- delete(H,B,U), insert(X,T,U). % Delete all elements from B.

permutation([],[]). % Base case.
permutation([H|T],P) :- permutation(Q,T), insert(H,Q,P). % P a permutation of T, H inserted.

我的想法是查询

?- insert(A,B,X). 

对于给定的 A,B 应该返回所有实例化 X 的方式,使其等于列表 B,其中添加了元素 A。但是,它不会这样做:

?- insert(3,[1,2],X).
X = [1, 2, 3] ;
X = [1, 3, 2] ;
ERROR: Out of global stack

我认为这是因为我定义谓词的方式,检查第三个参数中的列表减去第二个参数中列表的每个元素是否等于仅包含第一个参数的列表,而不是建设性地定义它,但是我很难以另一种方式解决这个问题。然后,排列谓词应检查其第二个参数中的列表是否是递归排列,方法是检查 P 是否是第一个列表的尾部的排列,其中头部随机插入。感谢您的帮助!

【问题讨论】:

  • 也许你可以问:“为什么我对insert/3 的定义被破坏了?”?
  • 您可以在github.com/SWI-Prolog/swipl/blob/master/library/lists.pl 中查看lists.pl,您可以在其中找到许多“教科书”谓词。我首先在 Sterling 和 Shapiro 的教科书“The Art of Prolog”中发现了这样的谓词。也许您可以阅读教科书?

标签: recursion prolog logic


【解决方案1】:

insert/3delete/3 都是同一个谓词,在教科书中可以找到 select/3。它也在标准库中,例如在 SWI-Prolog 中,您可以找到它为select/3。您可以使用它来插入删除,只需根据需要更改列表的位置即可。

从“abc”中删除“b”:

?- select(b, [a,b,c], X).
X = [a, c] ;
false.

在“ac”中任意位置插入“b”:

?- select(b, X, [a,c]).
X = [b, a, c] ;
X = [a, b, c] ;
X = [a, c, b] ;
false.

它的定义与您对delete/3 的定义完全相同,如果您在开源的 SWI-Prolog 中看到 lists.pl 的源代码,您就会看到它。

select(X, [X|Tail], Tail).
select(Elem, [Head|Tail], [Head|Rest]) :-
    select(Elem, Tail, Rest).

但是现在您可以像您描述的那样定义排列。因为我在同一个源文件lists.pl中也找到了这个,所以我只是将源代码复制到这里,因为它是开源的,所以没关系:

perm([], []).
perm(List, [First|Perm]) :-
    select(First, List, Rest),
    perm(Rest, Perm).

我使用lists:perm,因为它是“私有的”,但它不是私有的,只是没有导出:

?- lists:perm([a,b,c], P).
P = [a, b, c] ;
P = [a, c, b] ;
P = [b, a, c] ;
P = [b, c, a] ;
P = [c, a, b] ;
P = [c, b, a] ;
false.

?- lists:perm([a,b,c], [b,a,c]).
true ;
false.

我只有一条信息,那就是:阅读教科书并阅读源代码,因为它可以帮助您更快地学习。

【讨论】:

  • 我们需要自己编写这些谓词,这就是我没有使用内置谓词的原因。我根据我的删除谓词编写了插入,所以很高兴看到这被认为是一个好的定义。但是,插入或排列都不像我期望的那样工作。所以谢谢,但不幸的是你的回答并没有解决我的问题!
  • @Kermit 但你真正的问题是什么?这些谓词在几十年前的教科书中定义和描述,当时我还没有出生,我什至还不是很年轻。因此,只需拿起书阅读代码并学习即可。或者你也可以在 Stackoverflow 上提问,然后说你的问题没有解决,但问题到底是什么?
  • @Kermit 但是您是否看到不能基于“删除”编写“插入”,因为 Prolog 中的“插入”和“删除”是一回事?也许你可以定义insert(X, Y, Z) :- delete(X, Z, Y).
  • @Kermit 它不起作用,因为您定义错误。如果您研究了select/3 或您自己的delete/3 的定义,并且您了解为什么可以使用delete“插入”(这就是为什么“删除”不是一个好名字,而“插入”不是一个好名字! 但是select 是一个更好的名字)也许你理解你的错误?或者也许不是?
  • @Kermit 这也是为什么我在评论中写下您原来的问题“也许您可以提出问题:“为什么我对 insert/3 的定义被破坏了?”。因为如果您想知道为什么您对insert/3 的定义被破坏,那么您应该问“为什么我对insert/3 的定义被破坏”而不是“如何使用插入来编写排列”。也可能不是。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多