Prolog - 平均谓词:论证没有充分实例化

时间:2017-03-23 17:04:17

标签: list functional-programming prolog instantiation-error

我有一个汽车列表(德语自动),第一个变量是牌照,第二个是速度:

[auto(eu-ts884, 69), auto(dn-gh184, 64), auto(ac-lj123, 72)].

现在我尝试编写一个平均谓词,但它失败并显示错误消息:

  

错误:参数没有充分实例化

到目前为止我的代码:

durchschnitt([], 0, 0).
durchschnitt([auto(_, X)|Tail], L, Y):-
                        Y is S/L,
                        L > 0,
                        cardinal([auto(_, X)|Tail], L),
                        sumKilometer([auto(_, X)|Tail], S).


sumKilometer([], 0).
sumKilometer([auto(_, X)|Tail], Sum) :-
            sumKilometer(Tail, N),
            Sum is N + X.


cardinal([], 0).
cardinal([_|Tail], Result) :-
  cardinal(Tail, N),
  Result is N + 1.

我的代码与post相当,尽管我无法弄清楚我的错误。

注意sumKilometercardinal工作正常。

1 个答案:

答案 0 :(得分:2)

你写道:

durchschnitt([], 0, 0).
durchschnitt([auto(_, X)|Tail], L, Y):-
    Y is S/L,
    L > 0,
    cardinal([auto(_, X)|Tail], L),
    sumKilometer([auto(_, X)|Tail], S).

第一个问题是,当您致电durchschnitt([auto(foo,2)],L,Y)时, L是一个自由变量。因此,无法计算Y is S/L ,因为此处SL都未知。

但您可以使用:

durchschnitt([], 0, 0).
durchschnitt([auto(_, X)|Tail], L, Y):-
    cardinal([auto(_, X)|Tail], L),
    sumKilometer([auto(_, X)|Tail], S),
    Y is S/L.

因此,您可以计算LS已知之后的平均值。此外,您不会将列表与[auto(_,X)|Tail]等统一在一起。像A = [_|_]这样的简单检查就足够了:

durchschnitt([], 0, 0).
durchschnitt(A, L, Y):-
    A = [_|_],
    cardinal(A, L),
    sumKilometer(A, S),
    Y is S/L.

这也将减少打包解包所花费的时间。

总和,长度和平均值同时

您可以构造一个同时计算三个谓词的谓词(因此不会在列表上循环两次)。您只需使用 accumulators ,例如:

durchschnitt(A,L,Y) :-
    durchschnitt(A,0,0,L,Y).

这里第二个和第三个元素分别是运行总和和长度。

现在durchschnitt/5,有两种情况。在第一种情况下,我们已到达列表的末尾,因此我们必须计算平均值并将其返回,如:

durchschnitt([],S,L,L,Y) :-
    (L \= 0
    -> Y is S/L
    ; Y = 0).

所以我们使用if-then-else检查长度是否与0不同(如果列表中没有auto s,我们返回0平均值。

在递归的情况下,我们简单地递增运行长度并更新运行总和,如:

durchschnitt([auto(_,Si)|T],RS,RL,L,Y) :-
    RSN is RS+Si,
    L1 is L+1,
    durchschnitt(T,RSN,L1,L,Y).

或者把它放在一起:

durchschnitt(A,L,Y) :-
    durchschnitt(A,0,0,L,Y).

durchschnitt([],S,L,L,Y) :-
    (L \= 0
    -> Y is S/L
    ; Y = 0).
durchschnitt([auto(_,Si)|T],RS,RL,L,Y) :-
    RSN is RS+Si,
    L1 is L+1,
    durchschnitt(T,RSN,L1,L,Y).