Уже есть 3 SO-ответа, но я не могу согласиться ни с одним! Все они неверны.
Как избавиться от избыточных решений
Рассмотрим три факта в вашем определении:
mergeL([],[],[]).
mergeL(List, [], List).
mergeL([], List, List).
Все они преуспевают для mergeL([],[],[])
, который является источником ваших увольнений. Второй и третий факты связаны с тем, что List
является непустым списком. Итак, давайте добавим это к определению:
mergeL([],[],[]).
mergeL(List, [], List) :- List = [_|_].
mergeL([], List, List) :- List = [_|_].
Это устраняет избыточные решения. Нет необходимости в разрезе, чтобы удалить избыточные решения. Однако сокращения, представленные в другом SO-ответе, могут скрывать решения. Для запроса mergeL(Xs,YS,Zs)
есть ровно одно решение для урезанной версии, а их должно быть бесконечно много.
Как устранить оставшиеся точки выбора
Тем не менее, есть некоторый смысл в использовании сокращений: они могут удалить одну точку выбора. Но такой разрез должен быть защищен соответствующим образом, например:
mergeL(Xs, Ys, Zs) :-
( Xs == [], Ys == [] -> !
; Zs == [] -> !
; true
),
Xs = [], Ys = [], Zs = [].
...
Я не уверен, стоит ли это усилий... Реализация может предложить это более эффективно. Подробнее об этом см. это и это.
Хвостовая рекурсия
Гораздо интереснее для вас, наверное, изменение последнего правила. Скорее следует читать:
mergeL([X|Rest],[Y|Rest2], [XY|Res2]) :-
append(X,Y,XY),
mergeL(Rest, Rest2, Res2).
Это позволяет избежать временного выделения пространства локального стека. Так что это однозначно оптимизация. Но оптимизация, которая не повредит логическому чтению вашего предиката.
На моем 32-битном ноутбуке 2009 года (почти паровом) и SWI 6.3.3-40-g064f37b:
Оригинальная версия:
?- N is 2^20, length(L,N), maplist(=([]),L), time(mergeL(L,L,J)).
% 2,097,206 inferences, 5.232 CPU in 5.250 seconds (100% CPU, 400851 Lips)
Хвостовая рекурсивная версия:
?- N is 2^20, length(L,N), maplist(=([]),L), time(mergeL(L,L,J)).
% 2,097,152 inferences, 0.525 CPU in 0.526 seconds (100% CPU, 3997337 Lips)
Э-это коэффициент 10.
А теперь с более длинными списками: Хвостовая рекурсивная версия:
?- N is 2^22, length(L,N), maplist(=([]),L), time(mergeL(L,L,J)).
% 8,388,608 inferences, 4.228 CPU in 4.237 seconds (100% CPU, 1984272 Lips)
по сравнению с исходным порядком:
?- N is 2^22, length(L,N), maplist(=([]),L), time(mergeL(L,L,J)).
% 1,765,930 inferences, 1.029 CPU in 1.033 seconds (100% CPU, 1716119 Lips)
ERROR: Out of local stack
Таким образом, для заполнения локального стека было выполнено только 1,7Ми. Это в первую очередь космическая проблема! Если у вас больше памяти, чем у меня, просто увеличьте N is 2^22
!
person
false
schedule
15.11.2012