Prolog中的递归:加法变量

时间:2015-11-24 17:52:27

标签: recursion prolog

我真的不明白Prolog中的递归是如何工作的。假设您有以下两个功能:

my_length([],0).
my_length([_|T], Length) :-
    my_length(T, T_length),
    Length is T_length + 1.

my_nth0(Position, [Element|_], Element, Position).
my_nth0(Position, [_|Tail], X, CurrentPos) :-
    NextPos is CurrentPos + 1,
    my_nth0(Position, Tail, X, NextPos). 

我理解my_nth0:每次递归调用函数时,都会将NextPos增加1.但是,我不会低估my_length。我这样写:

my_length([],0).
my_length([_|T], Length) :-
    T_Length is Length + 1.,
    my_length(T, T_length).

这似乎与my_nth0的风格相同。但是,第一个看似正确的函数实现恰恰相反(它基本上就是T_length is Length - 1)。为什么这样做?

2 个答案:

答案 0 :(得分:2)

阅读my_length/2 从右到左的第二个条款!

  

如果 T的长度为T_length

     

然后 [_|T]的长度为T_length+1

答案 1 :(得分:1)

您是否真的尝试过my_length/2版本,看看会发生什么?修复语法错误(:)后,如果您查询my_length([1,2,3], N).,则会收到“变量未实例化的错误”,因为它会在T_Length is Length + 1没有问题时尝试评估Length有一个价值。因此,如果您使用is/2,则递归调用必须首先使Length具有递归调用的值,如第一个示例所示。

此外,在您的示例中,您尝试通过T_Length is Length + 1 增加变量,但您的递归基本案例的最终长度为0。你不能将长度“增长”到0

my_length([], 0).     % Base case is length = 0
my_length([_|T], Length) :-
    % Length is UNINSTANTIATED on my_length([1,2,3], N) query
    %  so the following 'is/2' will fail to evaluate
    T_Length is Length + 1,
    my_length(T, T_length).    % T_length > Length, but base case is 0!

或者,如果你使用了CLPFD并修正了长度与T_Length的评估顺序,你可以按照你要显示的顺序放置它:

my_length([], 0).
my_length([_|T], Length) :-
    % The following defines an arithmetic 'relation' between Length and T_Length
    %   and is permitted as a constraint
    Length #= T_Length + 1,
    my_length(T, T_length).

您还可以使用累加器来获取尾部递归,以便确实可以增加长度值,直到它到达结尾:

my_length(L, N) :-
    my_length(L, 0, N).

my_length([], N, N).    % Reached the length
my_length([_|T], A, N) :-   % Here, `A` is instantiated by design
    A1 is A + 1,        % So this is/2 expression will evaluate
    my_length(T, A1, N).