Пролог - средний предикат: аргументы недостаточно проработаны
У меня есть список автомобилей (auto на немецком языке), где первая переменная - номерной знак, а вторая - скорость:
[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.
Мой код вполне эквивалентен этому посту, хотя я не могу разобрать свою ошибку.
Примечание: sumKilometer
а также cardinal
работают нормально.
1 ответ
Ты пишешь:
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
так как оба S
а также L
здесь неизвестны.
Однако вы можете использовать:
durchschnitt([], 0, 0).
durchschnitt([auto(_, X)|Tail], L, Y):-
cardinal([auto(_, X)|Tail], L),
sumKilometer([auto(_, X)|Tail], S),
Y is S/L.
Таким образом, здесь вы рассчитываете среднее значение после обоих L
а также S
известны. Кроме того, вы не объединяете список с [auto(_,X)|Tail]
и т. д. Простая проверка вроде A = [_|_]
достаточно:
durchschnitt([], 0, 0).
durchschnitt(A, L, Y):-
A = [_|_],
cardinal(A, L),
sumKilometer(A, S),
Y is S/L.
Это также сократит время, затрачиваемое на упаковку и распаковку.
Сумма, Длина и Среднее все одновременно
Вы можете создать предикат, который вычисляет все три одновременно (без повторения цикла по списку). Вы можете просто использовать аккумуляторы, такие как:
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
в списке мы возвращаемся 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).