以非递归方式在prolog中获取列表的长度

以非递归方式在prolog中获取列表的长度,prolog,Prolog,我有下面的代码用于在prolog中获取列表的长度,它是递归工作的。 有没有其他方法来计算长度 len([], 0). len([H|T], N) :- len(T, NT), N is NT + 1. 任何建议都将不胜感激。这里是一个迭代解决方案,使用重复/0谓词: getlength(L,N) :- retractall(getlength_res(_)), assert(getlength_res(0)), retractall(getlength_list

我有下面的代码用于在prolog中获取列表的长度,它是递归工作的。 有没有其他方法来计算长度

len([], 0).
len([H|T], N) :-
    len(T, NT), N is NT + 1.

任何建议都将不胜感激。

这里是一个迭代解决方案,使用
重复/0
谓词:

getlength(L,N) :-
    retractall(getlength_res(_)),
    assert(getlength_res(0)),
    retractall(getlength_list(_)),
    assert(getlength_list(L)),
    repeat,
        (
            getlength_list([]), !, getlength_res(N)
        ;
            retract(getlength_res(V)), W is V + 1, assert(getlength_res(W)),
            retract(getlength_list([_|T])), assert(getlength_list(T)), fail
        ).
此解决方案在遍历列表时创建和收回事实
getlength\u res/1
getlength\u list/1
,用较短的列表替换旧列表,并在每次迭代
repeat/0
时用大于1的数字替换旧数字。在某种意义上,这两个动态断言/收回的事实的行为非常类似于命令式语言的可赋值变量


一般来说,Prolog中的迭代解比递归解更难理解。考虑到任何具有命令式编程语言赋值语句效果的东西都与Prolog的设计理念背道而驰,这一点并不奇怪。

你问错了问题:)

但是说真的:找到列表长度的唯一合理方法是使用内置的
length/2
。它的实现方式无关紧要——更重要的是它的语义:

?- length([a,b], 2).
true.

?- length([a,b], 4).
false.

?- length([a,b,c], Len).
Len = 3.

?- length(List, 3).
List = [_G937, _G940, _G943].

?- length(List, Len).
List = [],
Len = 0 ;
List = [_G949],
Len = 1 ;
List = [_G949, _G952],
Len = 2 . % and so on
不管怎样,都没有比这更简单的了。与使用
length/2
相比,查找列表长度、检查列表长度、创建特定长度的列表或枚举长度不断增加的列表的任何其他方法都不那么“简单”

然后:学习Prolog意味着学习如何使用
length/2
,以及其他良好的声明性内置程序


我相信你会想到
length/2的许多其他用法

很抱歉,我忍不住尝试了这个“挑战”:


findall/3正在进行幕后递归,代码正在统一列表FreeList和Input,直到它们统一为止

您可以使用内置谓词,
length(List,N)
:)为什么你需要它是非递归的?我正在学习prolog,我想知道在prolog中做简单的事情除了递归还有其他方法吗。内置谓词本身是否再次使用递归?内置谓词是否在prolog或其他语言中使用递归取决于prolog实现。有一些方法可以不递归地操作列表,但它通常涉及其他谓词,例如
append
maplist
、或
length
。这些可能在给定的Prolog实现中递归编写,也可能不递归编写。递归对于遍历列表中的所有元素至关重要。如果您只需要第一个元素,您可以执行类似于
[H | T]=List
的操作来获取头部(第一个)元素
H
,或者尾部列表
T
。我没有考虑
assert
方法(+1)。在这种情况下,它不仅更难阅读,而且效率也很低,而且不是推荐的替代品。:)@不用说,我强烈建议不要使用这类解决方案,因为这样做没有任何好处,执行速度较慢,语句数增加了7倍(是的,7倍)。谢谢你的评论!的确我只是想强调一下这个问题,因为我不确定OP在Prolog方面的经验水平。与使用
assert
retract
相比,在许多可能不太明显的情况下,列表处理更受欢迎。不过,我很喜欢这个答案,因为它说明了Prolog的这一方面。不,这只是在文字上玩得更多。
length/2
在许多实现中用于确定长度和检测周期,这确实是无与伦比的聪明。
Input=[a,b,b,b,b,b,b,b,b,a,b,c,d,f], between(1,inf,K),findall( _,between(1,K,_),FreeList), ( FreeList=Input,!,true).