简体   繁体   English

Prolog中计算列表长度的不同方法

[英]Different ways of computing list length in Prolog

Here are 4 different ways of computing list length in Prolog:以下是 Prolog 中计算列表长度的 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 - mathematically straightforward, works in all directions list_length1 - 数学简单,适用于所有方向
  • list_length2 - not sure what is this good for, created by analogy list_length2 - 不知道这有什么用,通过类比创建
  • list_length3 - last call optimized, works in one direction only list_length3 - 上次调用优化,仅在一个方向上工作
  • list_length4 - recursive, works in one direction list_length4 - 递归,单向工作

Is there any merit to list_length2 or list_length4 ? list_length2list_length4有什么优点吗?

list_length2 - not sure what is this good for, created by analogy list_length2 - 不知道这有什么用,通过类比创建

To better understand the difference between version 1 and 2, consider a generalization of the predicate.为了更好地理解版本 1 和 2 之间的区别,请考虑对谓词进行概括 A gross generalization.粗略的概括。 Simply add the facts list_length1(_,_).只需添加事实list_length1(_,_). and list_length2(_, _, _).list_length2(_, _, _). in front of their definitions.在他们的定义前面。 Now from a declarative viewpoint, these definitions get useless.现在从声明的角度来看,这些定义变得毫无用处。 But from a procedural viewpoint we now get some useful hints:但是从程序的角度来看,我们现在得到了一些有用的提示:

?- list_length1("abc",N).
   true
;  clpz:(_A+1#=N), clpz:(N in 1..sup), clpz:(_A in 0..sup)
;  clpz:(_A+1#=N), clpz:(_B+1#=_A), clpz:(N in 2..sup), clpz:(_A in 1..sup), clpz:(_B in 0..sup)
;  clpz:(_A+1#=N), clpz:(_B+1#=_A), clpz:(_C+1#=_B), clpz:(N in 3..sup), clpz:(_A in 2..sup), clpz:(_B in 1..sup), clpz:(_C in 0..sup)
;  N = 3.
?- list_length2("abc",N).
   clpz:(N in 0..sup)
;  clpz:(N in 1..sup)
;  clpz:(N in 2..sup)
;  clpz:(N in 3..sup)
;  N = 3.

So, version 1 has to create a chain of trivial arithmetical relations and their accompanied variables proportional to the length of the list that will get updated by each further inference and that will get collapsed in the very last moment, whereas version 2 is happy with a single domain (which in this case is infinite) that gets more and more constrained by each step.因此,版本 1 必须创建一系列微不足道的算术关系及其伴随的变量,这些变量与列表的长度成正比,这些变量将通过每次进一步的推理而更新,并且会在最后一刻崩溃,而版本 2 很满意单个域(在这种情况下是无限的)越来越受到每一步的约束。

(The operations related to I are effectively all trivial (is)/2 -computations.) (与I相关的操作实际上都是微不足道(is)/2计算。)

Try ?- list_length2(L,N), N = 10000. to see the difference performance-wise.尝试?- list_length2(L,N), N = 10000.查看性能方面的差异。

In theory, version 1 could kind of avoid the creation of these trivial relations and update a single variable avoiding the intermediary variables, but so far I have not seen a system capable of doing this.理论上,版本 1 可以避免创建这些琐碎的关系并更新单个变量以避免中间变量,但到目前为止我还没有看到能够做到这一点的系统。 And even if there would be such a system, version 1 would still be slower than version 2 which is just happy with a single variable.即使有这样的系统,版本 1 仍然会比版本 2 慢,后者只对单个变量感到满意。

Is there any merit to list_length4 ? list_length4有什么优点吗?

This version produces answers in a very costly, unnecessarily quadratic manner.这个版本以非常昂贵、不必要的二次方方式产生答案。 For each further answer of list_length4(L, N) it needs time proportional to the length of L .对于list_length4(L, N)的每个进一步答案,它需要与L的长度成比例的时间。 Try, eg ?- list_length3(L,N), N = 10000. and compare it to version 4.尝试,例如?- list_length3(L,N), N = 10000.并将其与版本 4 进行比较。

And for the mathematical straightforwardness, please consider to use (#)/1 in your programs.为了数学上的简单明了,请考虑在您的程序中使用(#)/1 So in stead of N #>= 0 just write #N #>= 0 .所以代替N #>= 0只需写#N #>= 0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM