Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List &引用;“堆栈外”;简单Prolog谓词错误_List_Prolog_Failure Slice - Fatal编程技术网

List &引用;“堆栈外”;简单Prolog谓词错误

List &引用;“堆栈外”;简单Prolog谓词错误,list,prolog,failure-slice,List,Prolog,Failure Slice,我一直在练习序言。我尝试编写的函数是compose(L1、L2、L3)。它由L1和L2元素按顺序交错组成,直到其中一个元素变为nil,然后在末尾附加非nil列表。当输入L1和L2时(即打印出正确的L3),函数工作得非常好,但当输入L3并尝试获取所有逻辑上可能的输入L1和L2时,我遇到了“堆栈外”错误。例如,对于以下功能代码 compose([],[],[]). compose(L1,[],L3):- append(L1,[],L3). compose([],L2,L3):- ap

我一直在练习序言。我尝试编写的函数是compose(L1、L2、L3)。它由L1和L2元素按顺序交错组成,直到其中一个元素变为nil,然后在末尾附加非nil列表。当输入L1和L2时(即打印出正确的L3),函数工作得非常好,但当输入L3并尝试获取所有逻辑上可能的输入L1和L2时,我遇到了“堆栈外”错误。例如,对于以下功能代码

compose([],[],[]).
compose(L1,[],L3):-
    append(L1,[],L3).
compose([],L2,L3):-
    append([],L2,L3).
compose([H1|T1],[H2|T2],L3):-
    compose(T1,T2,Tail),
    append([H1],[H2],Head), 
    append(Head,Tail,L3).

?-compose(L1,L2,[a,b,c]).
将给我一个堆栈外错误。我应该如何解决这个问题?

一个“全局堆栈外”错误通常意味着您的递归陷入无限循环中,因此一直调用谓词,直到堆栈耗尽

此处进入infinte循环的原因是,它将首先发出结果:

?- compose(L1,L2,[a,b,c]).
L1 = [a, b, c],
L2 = [] ;
L1 = [],
L2 = [a, b, c] ;
L1 = [a, c],
L2 = [b] ;
但随后它将寻找更多的解决方案。它根据您的程序,通过每次将第一项与
[H1 | T1]
统一,第二项与
[H2 | T2]
统一来实现这一点。然后立即进行递归调用,因此Prolog无法检查
H1
H2
是否实际上是第三个参数中的前两个元素

然而,我们首先不需要所有这些
append/3
调用等。我们可以对参数进行简单的统一:

compose([],L2,L2).
compose(L1,[],L1).
compose([H1|T1],[H2|T2],[H1, H2|T3]) :-
    compose(T1,T2,T3).
对于给定查询,该查询将在建议的解决方案出现后终止:

?- compose(L1,L2,[a,b,c]).
L1 = [],
L2 = [a, b, c] ;
L1 = [a, b, c],
L2 = [] ;
L1 = [a],
L2 = [b, c] ;
L1 = [a, c],
L2 = [b] ;
false.
实际上,由于递归,第三个参数最终将是一个空列表,因此无法与
[H1,H2 | T3]
列表统一

我应该如何解决这个问题

首先,试着理解为什么查询没有终止。您可以尝试想象Prolog是如何进行的,但请注意,这可能会变得相当复杂。毕竟,Prolog结合了两个控制流(AND-AND或控制),并且它有一些在更传统的语言(OO和FP)中不存在的部分未知数据。因此,我不喜欢模仿Prolog,而是让Prolog帮助我定位错误。为此,我在您的程序中添加了尽可能多的目标
false
,这样查询仍然不会终止。以下是最大值,称为a:

组合([]、[]、[]):-false。 组合(L1,[],L3):-false, 附加(L1、[]和L3)。 组合([],L2,L3):-false, 追加([],L2,L3)。 组成([H1 | T1]、[H2 | T2]、L3):- 合成(T1,T2,尾部),假, 附加([H1]、[H2],头部), 附加(头部、尾部、L3)。 -组成(L1,L2,[a,b,c]),假。 我们可以跳过你的第一个条款。只有最后一条规则的第一个目标才有意义!因此,无非是:

compose([H1|T1],[H2|T2],L3):- compose(T1,T2,Tail), false, ... . ?- compose(L1, L2, [a,b,c]), false. 组成([H1 | T1]、[H2 | T2]、L3):- 合成(T1,T2,尾部),假, ... . -组成(L1,L2,[a,b,c]),假。 在这个小程序中,
compose/3
的第三个参数被完全忽略。没有人想要
L3
。因此,
L3
对终止没有影响。要使此终止,我们需要在目标之前以某种方式约束
L3
。这本书告诉你怎么做


(此方法适用于纯Prolog程序的任何非终止问题,有关更多信息,请参阅。)

首先将其作为更简单但完全等效的方法重新编写

compose([]、[]、[])。%这里有些冗余
组成(L1,[],L1)。
组成([],L2,L2)/*
组成([H1 | T1]、[H2 | T2]、L3):-%整个溶液
组成(T1,T2,尾部),
水头=[H1,H2],
L3=[头|尾]*/
现在可以清楚地看出问题在于递归,首先计算结果的其余部分(
Tail
),然后完成它(如
L3

相反,扭转它

compose([H1 | T1],[H2 | T2],[H1,H2 | Tail]):-%单步
组成(T1,T2,尾部)。
现在我们有了共递归,并且是一个有效的递归。它首先创建结果的开始部分(肯定是有限的),然后填充缺少的部分


(在上面,“creates”可以与“consumes”互换,这是Prolog的双向性质。作为一个单步,它不关心哪些参数被使用,哪些参数被产生)。

你所说的等价是什么意思?原始程序在编写(1,[],L)时失败,但您的程序成功。所以,至少在这个特定的情况下,它们是不同的。像往常一样,我对类型很马虎,忽略了错误的键入错误,试图解决问题的核心。因此,如果谓词按预期使用,我想这是等价的。在程序不正确的情况下,“按预期”的模糊概念有多大帮助?不终止的原因很可能是这些附件中的一个,我看不出您可以跳过它们的原因。(顺便说一句,我不是这样的。)添加
L1=[| |]
以避免像
compose([a],[b],L)
这样的查询的冗余。请参见: compose([H1|T1],[H2|T2],L3):- compose(T1,T2,Tail), false, ... . ?- compose(L1, L2, [a,b,c]), false.