Процедура размера на языке Пролог

Я новичок в Прологе и не настолько хорош, когда речь заходит о рекурсивных алгоритмах, как есть, поэтому меня смущают следующие два предложения:

size([], 0).
size([H|T], N) :- size(T, N1), N is N1+1.

У меня проблемы с отслеживанием этой проблемы:

?- size([a,b,c,d], N).

Это объединится со вторым предложением, чтобы сформировать:

size([a,b,c,d], N) :- size([b,c,d], N1), N is N1+1.

Но меня смущает N является N1+1 поскольку эти переменные никогда не объединяются. Какие значения принимают эти переменные?

Любая помощь по этому вопросу, или простой след этого алгоритма, будет принята с благодарностью.

1 ответ

N равно N1+1, поскольку эти переменные никогда не объединяются.

Я думаю, вы имеете в виду, что они никогда не создаются, то есть никогда не получают значения. Объединение двух переменных может создавать их экземпляры, но это не обязательно. Например, вы можете запустить это в прологе REPL:

?- N = N1.
N = N1.

в то время как N а также N1 не имеют значения (пока), они едины; если N1 будет создан позже, N будет создан с тем же значением. Еще один, менее тривиальный пример:

?- [H|T] = L, L = [1|M], writeln(H).
1
H = 1,
T = M,
L = [1|M].

Тем не менее, это правда, что N никогда не объединяется с N1+1! is будет оценивать N1+1 и это значение будет объединено с N, Это произойдет после внутреннего size([b,c,d],N1) был оценен так N1 переменная будет создана.

По сути, выполнение будет так:

size([a,b,c,d],N).
          size([b,c,d],N1)
               size([c,d],N1)
                   size([d],N1)
                        size([],0)
                        N is 0+1.
                   N is 1+1.
               N is 2+1.
          N is 3+1.

Что немного неэффективно, так как нам нужно хранить все вызовы функций в памяти; посмотрите на хвостовую рекурсию и аккумуляторы, чтобы это исправить.

Также обратите внимание, что N1 нужно создавать только потому, что is собирается оценить выражение. Вы могли бы написать что-то вроде этого:

size([],0).
size([_|T], 1+ N1):-size(T,N1).

и если вы называете это:

?- size([1,2],N).
N = 0+1+1.

Веселье, не правда ли? Вы можете оценить последний N, например, назвать его как size([1,2],N), Result is N, Тем не менее, одна проблема заключается в том, что мы держим цепочку 0+1+1+1+1+...... в памяти, которая может стать большой очень быстро. Так что лучше всего использовать этот трюк для вещей, которые не будут расти, например, шаблонов выражений.

Другие вопросы по тегам