List 在prolog中相交2个列表

List 在prolog中相交2个列表,list,prolog,List,Prolog,我的任务是在prolog中将两个列表相交。然而,我似乎找不到我的功能不工作的原因。我不知道prolog想从我这里得到什么。这是我试图解决的任务: write_list([]). write_list([Head|Tail]) :- write(Head), nl, write_list(Tail). intersect(L,[],X) :- write_list(X). intersect([],L,X) :- write_list(X). intersect([H1|T1],[

我的任务是在prolog中将两个列表相交。然而,我似乎找不到我的功能不工作的原因。我不知道prolog想从我这里得到什么。这是我试图解决的任务:

write_list([]).


write_list([Head|Tail]) :-
  write(Head), nl,
  write_list(Tail).

intersect(L,[],X) :- write_list(X).
intersect([],L,X) :- write_list(X).

intersect([H1|T1],[H2|T2], X) :-
    H1 == H2,
    append([H1],X,Y),
    intersect(T1,T2,Y).

intersect([H1|T1],[H2|T2], X) :-
    H1 > H2,
    intersect(T1,[H2|T2],X).

intersect([H1|T1],[H2|T2], X) :-
    H1 < H2,
    intersect([H1|T1],T2,X).
write_列表([])。
写下列表([Head | Tail]):-
写(头),nl,
写下清单(尾部)。
相交(L,[],X):-写入列表(X)。
相交([],L,X):-写入列表(X)。
相交([H1 | T1],[H2 | T2],X):-
H1==H2,
附加([H1],X,Y),
相交(T1,T2,Y)。
相交([H1 | T1],[H2 | T2],X):-
H1>H2,
相交(T1[H2 | T2],X)。
相交([H1 | T1],[H2 | T2],X):-
H1
我试着把它叫做intersect([1,2,3],[2,3,4],X)。我得到的答案是
[]
。谁能告诉我为什么


更新1:另一个附带问题是,我如何在不调用write_list(X)的情况下让prolog打印X。我看到一些函数返回额外的参数…

让我们用逻辑语言来思考这个问题。
intersect(X,Y,Z)
的意思可能是,
Z
X
Y
的交集。因此,
intersect(L,[],X):-write_list(X)的基本情况是不正确的,除非
X=[]
。对于基本情况,我们可以说:

intersect([], _, []).
因为任何东西(
)与空集(
[]
)相交都是空的

对于递归情况,您有:

intersect([H1|T1],[H2|T2], X) :-
    H1 == H2,
    append([H1],X,Y),
    intersect(T1,T2,Y).
让我们稍微简化一下,因为我们可以将列表头的统一放在谓词的头中,并且我们不需要
append
,因为
append([H1],X,Y)
与,
[H1 | X]=Y

intersect([H|T1],[H|T2], X) :-
    intersect(T1, T2, [H|X]).
我们已经遇到了一些麻烦,因为递归调用的结果应该是较短的列表。它的意思可能是:

intersect([H|T1],[H|T2], [H|X]) :-
    intersect(T1, T2, X).
但即便如此,尽管有所改进,但它还是假设相同的元素将在两个列表中相互串联,而事实可能并非如此

另一种方法是使用
member/2
delete/3

intersect([], _, []).
intersect([H|X], Y, Z) :-
    member(H, Y)
->  delete(Y, H, Y1),
    intersect(X, Y1, Z1),
    Z = [H|Z1]
;   intersect(X, Y, Z).
这里,如果第一个列表的当前头是第二个列表的成员,我们将从第二个列表中删除该元素的所有引用,并确定该结果与第一个列表的其余部分的交集,这将成为子句结果的尾部。否则,我们将第一个列表的尾部与第二个列表的尾部相交

请注意,这是解决问题的一种有点必要(可能有点幼稚)的方法,在必要的意义上起作用,“给定两个列表X和Y,找到它们的交点”。但它不是关系式或声明式的(“Z是X和Y的交集”),这将是Prolog的真正优势


至于您关于避免“写入”结果的问题,您可以看到,当您在prolog中执行谓词时,它将向您显示使其成为真的变量的可能实例。因此无需编写。

当递归返回到空列表时,您没有基本情况。
相交([],X,…)
相交(X,[],…)
的结果是什么?在您的示例中,您的结果不仅是
[]
,而且如果列表长度不同,它将完全失败。还有几个旁注:
append([H1],X,Y)
可以简化为,
[H1 | X]=Y
,您可以使用
dif(H1,H2)
而不是单独检查
H1
H2
。使用
dif/2
也可以对非数字元素起作用。啊,你说得对,当我出于愤怒而删除这些案例时,我也删除了这些案例。这是我的更新代码。结果是一样的:[]基本情况是错误的。你必须考虑
intersect(X,Y,Z)
的含义,也就是说,
Z
X
Y
的交集。当然,
X
不是
L
[]
的交叉点,除非
X=[]
。递归将“展开”以给出结果。你的基本情况是在所有“退绕”发生之前发生的情况。只需调用
intersect([1,2,3],[2,3,4],X)即可避免
write
和prolog将告诉您
X
是什么。相交(L,[],[])。因为在这种情况下,X应该具有的值是[]?或者只是
intersect([],[uu,[])
intersect([uu,[],[])
,因为您不关心
L
是什么。你的主要案例需要重新配置,因为它在逻辑上是不正确的。如果
Y
[H1 | X]
(这是您通过
附加
得到的,那么
Y
不一定也是
T1
T2
交叉的结果,因为在这种情况下,
T1
T2
都需要包含
H1