Recursion 使用插入元素的Prolog置换谓词

Recursion 使用插入元素的Prolog置换谓词,recursion,prolog,logic,Recursion,Prolog,Logic,我试图编写一个谓词permutation/2,当且仅当两个参数都是list,一个是另一个的排列时,它才是真的。为此,我编写了两个helper谓词delete/3和insert/3。第一个为true,当且仅当第三个参数是第二个参数时,这两个参数都列出,并且删除了第一个参数中元素的第一个实例。当且仅当第三个参数等于插入第一个参数(元素)的第二个参数时,第二个参数为真 delete(X,[X|T],T). % Base case, element equals head. delete(X,[A|B]

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

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和
delete/3
都是同一谓词,在教科书中可以找到它,与
select/3
相同。它也在标准库中,例如在SWI Prolog中,您可以在
select/3
中找到它。您可以使用它来插入或删除,只需根据需要更改列表的位置

从“abc”中删除“b”:

在任何位置的“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.

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

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

从“abc”中删除“b”:

在任何位置的“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.

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

也许你可以问这样一个问题:“为什么我对
insert/3
的定义被破坏了?”?你可以看到lists.pl,其中有许多“教科书”谓词。我第一次在斯特林和夏皮罗的教科书《序言的艺术》中发现了这样的谓词。也许你们可以阅读教科书?也许你们可以问这样一个问题:“为什么我对
insert/3
的定义被破坏了?”?你们可以看到lists.pl,在这里你们可以找到许多“教科书”谓词。我第一次在斯特林和夏皮罗的教科书《序言的艺术》中发现了这样的谓词。也许你可以阅读教科书?我们被要求自己编写这些谓词,这就是为什么我没有使用内置谓词的原因。我基于delete谓词编写了insert,所以很高兴看到这被认为是一个好的定义。然而,无论是插入还是置换都不能像我期望的那样起作用。所以,谢谢,但不幸的是,你的回答并不能解决我的问题@克米特,但你真正的问题是什么?这些谓词是几十年前在教科书中定义和描述的,当时我还没有出生,甚至不再很年轻。因此,只要拿着这本书,阅读代码并学习。或者你也可以问一些关于Stackoverflow的问题,然后说你的问题没有解决,但问题到底是什么?@Kermit但是你看到你不能在“delete”的基础上写“insert”,因为Prolog中的“insert”和“delete”是一回事吗?也许你可以定义
insert(X,Y,Z):-delete(X,Z,Y)。
@Kermit它不起作用,因为你定义错了。如果您研究了
select/3
或您自己的
delete/3
的定义,并且理解了为什么您可以使用
delete
来“插入”(这就是为什么“delete”不是一个好名字,“insert”不是一个好名字!但是
select
是一个更好的名字)而您可能理解了您的错误?或者可能不是?@Kermit,这也是为什么我在评论中写到你最初的问题“也许你可以问一个问题:“为什么我对insert/3的定义被破坏了?”。因为如果你想知道为什么你对
insert/3
的定义被破坏了,你应该问“为什么我对
insert/3
的定义被破坏了”,而不是“如何使用插入编写排列”。也许不是。我们需要自己编写这些谓词,这就是为什么我没有使用内置谓词。我基于delete谓词编写了insert,所以很高兴看到这被认为是一个好的定义。然而,无论是插入还是置换都不能像我期望的那样起作用。所以,谢谢,但不幸的是,你的回答并不能解决我的问题@克米特,但你真正的问题是什么?这些谓词是几十年前在教科书中定义和描述的,当时我还没有出生,甚至还不是很年轻