错误:未处理的异常:超出本地堆栈-Prolog

错误:未处理的异常:超出本地堆栈-Prolog,prolog,Prolog,我试图用Prolog编写一个简单版本的length/3 如果您看一下length/2的标准实现,它如下所示: length([], 0). length([Head|Tail], N) :- length(Tail, N1), N is 1+N1. 虽然我的代码使用了几乎相同的想法,但我得到了错误“出本地堆栈”,我认为这是因为深层递归。我不明白为什么。我的代码是: mylength(_, [], 0). mylength([H1|T1], [H1copy|T1copy], N)

我试图用Prolog编写一个简单版本的
length/3

如果您看一下
length/2的标准实现,它如下所示:

length([], 0).
length([Head|Tail], N) :-
    length(Tail, N1),
    N is 1+N1.
虽然我的代码使用了几乎相同的想法,但我得到了错误“出本地堆栈”,我认为这是因为深层递归。我不明白为什么。我的代码是:

mylength(_, [], 0).
mylength([H1|T1], [H1copy|T1copy], N) :-
    mylength([H1|T1], [T1copy], N1),
    N is N1 + 1.

您的谓词
mylength/3
有以下问题。我想 您希望以
mylength(+、-、-)
模式运行它。然后是 第一个参数不下降的情况

问题是第二个子句,其中第一个参数
[H1 | T1]
在head中,未更改地传递给相同的第一个参数 谓词,与length/2中发生的相反。因而发生的 在无限递归中,由于给定的第二个参数
[T1copy]
没有 匹配第一个子句

无限递归可能导致内存耗尽,因为 示例每次调用都将为H1copy生成一个新变量。 特定的错误消息取决于Prolog系统

再见

旁白:阿莱迪看到可能有什么不对劲 当查询谓词时。一个人会得到单身警告 对于
h1,复制

但例如,在最新的SWI Prolog版本中 本地堆栈外错误将需要一些时间,因为 SWI Prolog不执行carbage收集。在^C和g之后 我明白了:

欢迎使用SWI Prolog(多线程,64位,7.1.16版)
版权所有(C)1990年至2014年阿姆斯特丹大学,阿姆斯特丹
行动(h寻求帮助)?目标
[552959]我的长度([1,2,3],[]],_G40)
[552958]我的长度(“”,,_G40)
[552957]我的长度(“”,,_G40)
[552956]我的长度(“”,,_G40)
[552955]我的长度(“”,,_G40)
我猜上面的意思是目前 在这里,我打断了Prolog解释器 调用堆栈的深度已经达到552959,即一半 一百万

在运行了几分钟后,我得到了以下结果
SWI Prolog中的错误消息:
错误:超出本地堆栈

您将
T1copy
放入列表中。将
[T1copy]
修改为
T1copy
mylength/3
应该准确描述什么?似乎你想要另一个相同长度的列表。这有点复杂:)无论如何:注意你对
length/2
的第一个定义不是“标准实现”!对于
长度(L,2)
的定义循环!但是它应该只给出一个答案
L=[\uu,\u]
。是的,我知道了,谢谢。P.S.:这个例子对于生成堆栈跟踪的prolog系统来说是一个相当大的挑战,因为堆栈跟踪将是巨大的。
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.1.16)
Copyright (c) 1990-2014 University of Amsterdam, VU Amsterdam

Action (h for help) ? goals

[552,959] mylength([1, 2, 3], [[]], _G40)
[552,958] mylength('<garbage_collected>', '<garbage_collected>', _G40)
[552,957] mylength('<garbage_collected>', '<garbage_collected>', _G40)
[552,956] mylength('<garbage_collected>', '<garbage_collected>', _G40)
[552,955] mylength('<garbage_collected>', '<garbage_collected>', _G40)