Проследим:
?- trace, del(5, [3,4,5,6,7], X).
Call: (7) del(5, [3, 4, 5, 6, 7], _G218) ? creep
Call: (8) 5\=3 ? creep
Exit: (8) 5\=3 ? creep
Call: (8) del(5, [4, 5, 6, 7], [_G344]) ? creep
Call: (9) 5\=4 ? creep
Exit: (9) 5\=4 ? creep
Call: (9) del(5, [5, 6, 7], [[]]) ? creep
Fail: (9) del(5, [5, 6, 7], [[]]) ? creep
Fail: (8) del(5, [4, 5, 6, 7], [_G344]) ? creep
Fail: (7) del(5, [3, 4, 5, 6, 7], _G218) ? creep
false.
Таким образом, вы можете видеть, что ваш код действительно не работает, когда он достигает 5, потому что 5 \= 5
ложно. Ваше первое правило никогда не выполняется, потому что список содержит более одного элемента. Второе правило повторяется «правильно» после нахождения 5 \= 3
и 5 \= 4
, но поскольку у вас нет 5 = 5
регистра ни в одном из ваших правил, сбой происходит там.
Кстати, давайте посмотрим, что будет, если 5 не окажется в списке:
?- trace, del(5, [3,4,6,7], X).
Call: (7) del(5, [3, 4, 6, 7], _G350) ? creep
Call: (8) 5\=3 ? creep
Exit: (8) 5\=3 ? creep
Call: (8) del(5, [4, 6, 7], [_G473]) ? creep
Call: (9) 5\=4 ? creep
Exit: (9) 5\=4 ? creep
Call: (9) del(5, [6, 7], [[]]) ? creep
Fail: (9) del(5, [6, 7], [[]]) ? creep
Fail: (8) del(5, [4, 6, 7], [_G473]) ? creep
Fail: (7) del(5, [3, 4, 6, 7], _G350) ? creep
false.
Вот почему я сказал «правильно» раньше: ваш индуктивный случай тоже неверен. Во-первых, у вас есть del(Ele, T, [New])
, но наверху у вас del(Ele, [H|T], [H|New])
, поэтому вы разворачиваете список еще раз справа (вот почему в нашей трассировке есть [[]]
). Но @false затрагивает более серьезную проблему, заключающуюся в том, что вы просто никогда не учитываете случай, когда вы действительно находите то, что хотите удалить. :) Вы также не обрабатываете случай, когда список пуст.
Это досадный факт из жизни, что обход структур данных и просмотр каждого элемента будет O (N). Еще один досадный факт заключается в том, что в функциональных и декларативных языках (языках, в которых отсутствуют «присваиваемые») изменение списка означает копирование хотя бы части списка. В Prolog есть более эффективные способы сделать это (например, вы можете использовать списки различий), но они будут иметь одну и ту же основную проблему. Эффективность Пролога - довольно большая тема. Я бы посоветовал вам не беспокоиться об этом слишком сильно заранее, но это может довольно быстро стать вашей проблемой. Но в этом случае нет, на самом деле нет более эффективного подхода с использованием деструктивных обновлений.
person
Daniel Lyons
schedule
19.03.2013