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

时间:2014-12-30 17:14:43

标签: prolog

我有以下代码来获取prolog中列表的长度,它以递归方式工作。 有没有其他方法来获得长度?

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

任何建议都将不胜感激。

3 个答案:

答案 0 :(得分:4)

你问的是错误的问题:)

但严肃地说:找到列表长度的唯一合理方法是使用内置的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,并且可以使用其他很好的声明性内置函数。

Repeating an element N times

Splitting a list into segments of some length

Exactly one pair in a list

Rotate a list

我相信你可以想到length/2的许多其他用途。

答案 1 :(得分:2)

这是一个使用repeat/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_res/1getlength_list/1,因为它遍历列表,将旧列表替换为较短的列表,旧号码的数字大于1 repeat/0的迭代。从某种意义上说,这两个动态断言/收回的事实与命令式语言的可分配变量非常相似。

Demo.

一般来说,Prolog中的迭代解决方案比它们的递归对应方更难阅读。考虑到任何具有命令式编程语言的赋值语句效果的东西都与Prolog的设计理念相悖,这一点也不足为奇。

答案 2 :(得分:0)

抱歉,我无法抗拒尝试这个"挑战":

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).

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