Prolog中的列表长度

标签 list prolog clpfd

我是 Prolog 编程的初学者。
我编写了这个程序来计算列表的长度。为什么下面的程序是错误的?

length(0, []).
length(L+l, H|T) :- length(L, T).

我写了下面的程序,它工作正常。
length([], 0).
length([H|T], N) :- length(T, N1), N is N1+1.

当我更改订单时,出现错误。为什么?
length([], 0).
length([H|T], N) :- N is N1+1, length(T, N1).

最佳答案

您需要使用累加器。虽然你可以做这样的事情:

list_length([]     , 0 ).
list_length([_|Xs] , L ) :- list_length(Xs,N) , L is N+1 .

这将一直递归到列表的末尾,然后在每次调用返回时,将长度加一,直到返回到具有正确结果的顶层。

这种方法的问题在于每次递归都会在堆栈上推送一个新的堆栈帧。这意味着如果列表足够长,您将 [最终] 耗尽堆栈空间。

相反,使用尾递归中介,如下所示:
list_length(Xs,L) :- list_length(Xs,0,L) .

list_length( []     , L , L ) .
list_length( [_|Xs] , T , L ) :-
  T1 is T+1 ,
  list_length(Xs,T1,L)
  .

这段代码种子一个带有累加器的工作谓词,种子为 0。在每次递归时,它创建一个新的累加器,其值为当前值 + 1。当到达列表末尾时,累加器的值与想要的结果。

prolog 引擎足够聪明(TRO/Tail Recursion Optimization),可以看到它可以在每次调用时重用堆栈帧(因为在递归调用之后没有使用任何局部变量),从而巧妙地将递归转换为迭代。

关于Prolog中的列表长度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19230594/

相关文章:

python - 按两个键对字典列表进行排序

prolog - 依赖规则顺序

list - 我应该如何删除列表中的非数字使用序言

python - 如何仅打印包含子字符串的行

Python函数替换输入变量

c# - 将自定义列表属性绑定(bind)到 DatagridView

当只存在一个时,Prolog 会尝试找到多个解决方案

list - 如何避免 SWI-Prolog 中的 "out of global stack"错误?

prolog - 如何使用成员谓词在序言中指定约束

list - 与 2 个示例相关的参数未充分实例化