Prolog - 平均谓词:未充分实例化的参数

Prolog - average predicate: Arguments not sufficiently instantiated

我有一个汽车列表(德语为 auto),其中第一个变量是车牌,第二个变量是速度:

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

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

ERROR: Arguments are not sufficiently instantiated

到目前为止我的代码:

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 工作正常。

你写:

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),
    <b>Y is S/L</b>.

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

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

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

同时求和、长度和平均值

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

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

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

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

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

所以我们使用 if-then-else 来检查长度是否与 0 不同(如果列表中没有 auto,我们 return 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).