Prolog列表长度四种计算实现及list_length2、list_length4价值问询
Prolog 列表长度的4种实现方式
以下是基于clpz库的4种列表长度计算实现代码:
:- use_module(library(clpz)). list_length1([], 0). list_length1([_|T], N) :- N #> 0, N1 #= N - 1, list_length1(T, N1). list_length2(A, N) :- N #>= 0, list_length2(A, 0, N). list_length2([], N, N). list_length2([_|T], I, N) :- I #< N, I1 #= I + 1, list_length2(T, I1, N). list_length3(A, N) :- list_length3(A, 0, N). list_length3([], N, N). list_length3([_|T], I, N) :- I1 is I + 1, list_length3(T, I1, N). list_length4([], 0). list_length4([_|T], N) :- list_length4(T, N0), N is N0 + 1.
各实现的基础特性如下:
list_length1:数学逻辑直观易懂,支持全方向运行list_length2:基于累加器+约束逻辑编写,适用场景待明确list_length3:支持尾调用优化,仅支持单向运行(传入列表求长度)list_length4:基础递归实现,仅支持单向运行
list_length2与list_length4的实际应用价值
两个实现都有明确的适用场景,不存在无价值的冗余写法:
list_length4的价值集中在教学场景
这是最贴合递归数学归纳定义的写法:空列表长度为0,非空列表长度是尾部列表长度加1,逻辑直白,不需要引入累加器、约束这类额外概念,是给Prolog初学者讲解递归逻辑的最佳示例。但生产环境几乎不会直接用——它不是尾递归,递归深度和列表长度完全绑定,处理长列表会直接触发栈溢出,而且因为用is做算术求值,完全不支持反向调用(比如传入长度生成对应长度的列表),通用性很差。list_length2是实用性很强的全方向实现
这个写法本质是加了约束边界的尾递归全方向版本,核心优势是所有调用模式下都能保证终止。对比同是全方向实现的list_length1:如果调用时N是未绑定变量,list_length1会从0开始无限枚举所有可能长度的列表,永远不会停止;而list_length2从入口就加了N #>= 0的约束,递归过程中用I #< N做边界判断,不管是传入列表算长度、传入固定长度生成列表、还是校验列表和长度是否匹配,都不会出现无限递归。
这种特性在约束求解、基于属性的测试、测试用例生成场景里非常好用:比如你要生成长度在0到20之间的所有测试列表,只要给N加N in 0..20的约束直接调用即可,不需要额外写边界控制逻辑,尾递归的特性也保证它处理长列表不会栈溢出。
内容的提问来源于stack exchange,提问作者vasily
相关产品推荐
相关产品推荐

