我有以下代码来获取prolog中列表的长度,它以递归方式工作。 有没有其他方法来获得长度?
len([], 0).
len([H|T], N) :-
len(T, NT), N is NT + 1.
任何建议都将不胜感激。
答案 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
,并且可以使用其他很好的声明性内置函数。
Splitting a list into segments of some length
我相信你可以想到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/1
和getlength_list/1
,因为它遍历列表,将旧列表替换为较短的列表,旧号码的数字大于1 repeat/0
的迭代。从某种意义上说,这两个动态断言/收回的事实与命令式语言的可分配变量非常相似。
一般来说,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进行统一,直到它们统一为止