Prolog语言中的大小过程

时间:2016-05-09 20:54:57

标签: list recursion prolog

我是Prolog的新手,并且在递归算法方面并不是那么好,因此我对以下两个条款感到困惑:

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

我无法追踪此问题:

?- size([a,b,c,d], N).

这将与第二个条款统一起来形成:

size([a,b,c,d], N) :- size([b,c,d], N1), N is N1+1.

但我对NN1+1感到困惑,因为这些变量永远不会统一。这些变量有什么价值?

非常感谢有关此问题的任何帮助,或该算法的简单描述。

1 个答案:

答案 0 :(得分:4)

  

N是N1 + 1,因为这些变量永远不会统一。

我认为你的意思是他们永远不会被实例化,即他们永远不会获得价值。统一两个变量可以实例化它们,但这不是必需的。例如,您可以在prolog REPL中运行它:

?- N = N1.
N = N1.

虽然NN1没有价值(但尚未),但它们是统一的;如果N1稍后被实例化,N也将被实例化为具有相同的值。另一个不那么琐碎的例子:

?- [H|T] = L, L = [1|M], writeln(H).
1
H = 1,
T = M,
L = [1|M].

但是,N永远不会与N1+1统一! is将评估N1+1 值将与N统一。这将在评估内部size([b,c,d],N1)之后发生,因此N1变量将被实例化。

基本上,执行将是这样的:

size([a,b,c,d],N).
          size([b,c,d],N1)
               size([c,d],N1)
                   size([d],N1)
                        size([],0)
                        N is 0+1.
                   N is 1+1.
               N is 2+1.
          N is 3+1.

由于我们需要将所有函数调用保留在内存中,因此效率有点低;查看尾递归和累加器来解决这个问题。

另请注意,N1只需要实例化,因为is将评估表达式。你可以这样写:

size([],0).
size([_|T], 1+ N1):-size(T,N1).

如果你打电话:

?- size([1,2],N).
N = 0+1+1.
有趣,不是吗?您可能想要评估最后一个N,例如将其称为size([1,2],N), Result is N。然而,一个问题是我们在内存中保留了一个0+1+1+1+1+......链,它可以非常快速地变大。所以最好将这个技巧用于那些不会增长的东西,例如:表达模板。