Рекурсивный предикат продолжается после достижения базового варианта - PullRequest
0 голосов
/ 09 декабря 2018

Я пытаюсь написать предикат 'range', который создает список целых чисел в указанном диапазоне.

Пример:

range(4,9, L).
L = [4,5,6,7,8,9]

Кажется, что я написал предикатработает правильно, но когда он заканчивается, у меня есть возможность нажать «Далее», а затем он возвращает:

L = [4, 5, 6, 7, 8, 9, _1200 | _1202]

Вот мой код:

range(Low, Low, [Low]). %base case, if low and high are equal 
range(Low, High, [H|T]):-
    Low > High,
    !;          %if low is greater than high cut
    H is Low,   %set the head of the list
    Num is Low + 1, %increment low by 1
    range(Num, High, T).    %recursive call

Я также хочу, чтобы он возвращал пустой список, если указан недопустимый диапазон.Например:

range (10, 4, L).

должен возвращать пустой список.Вместо этого я получаю:

L = [_1164 | _1166]

Как я могу настроить это так, чтобы он возвращал пустой список, а не (то, что я предполагаю, чтобы быть) адреса для головы и хвоста.

Вот как это выглядит при трассировке:

Trace

Ответы [ 2 ]

0 голосов
/ 09 декабря 2018

Вы написали точку с запятой (;) после разреза (!) вместо запятой (,).Точка с запятой в некоторой степени эквивалентна «логическому» или «логическому», поэтому вы написали что-то вроде:

range(A, A, [A]).
range(A, B, [C|E]) :-
    (   A>B, !
    ;   C is A,
        D is A+1,
        range(D, B, E)
    ).

Для range(1, 2, L) в основном есть два пути, которые дают решение (это не стандартная записьздесь он используется только для того, чтобы дать некоторое представление о том, как Пролог получает результаты:

range(1, 2, [C|E])
    C is 1,
    D is 2,
    range(2, 2, E) :-
        range(2, 2, [2]).             % we found a solution
        range(2, 2, [C|E])
            C is 2,
            D is 3,
            range(3, 2, E) :-
                range(3, 2, [C|E])
                3 > 2.                 % we found a solution 

Срез не останавливает выполнение предложения, а срез означает, что Пролог не будетрассмотрим следующие предложения для этого конкретного вызова (поэтому, если мы выполняем рекурсию, разрез не влияет на саму рекурсию). Поскольку других предложений нет, то отсечение здесь, таким образом, не оказывает влияния.

Мы можем упростить код до:

range(A, A, [A]).
range(A, B, [A|T]) :-
    A < B,
    A1 is A+1,
    range(A1, B, T).

Или мы можем использовать встроенный between/3 [swi-doc] и использоватьfindall/3 [swi-doc] сверх этого:

range(A, B, L) :-
    findall(X, between(A, B, X), L).
0 голосов
/ 09 декабря 2018

Вы можете упростить поток управления, например

range(Low, Low, [Low]). %base case, if low and high are equal
range(Low, High, [Low|T]):- %set the head of the list
    Low < High,
    Num is Low + 1, %increment low by 1
    range(Num, High, T).    %build the tail

Теперь второе предложение будет охватывать только предполагаемый случай.

О вашем решении, когда условие Low>High успешно , сокращение также успешно , а переменные в [H|T] не получают привязок (остается необработанными), в то время как предложение также успешно выполняется.Исправление приведет к сбою правила:

range(Low, Low, [Low]). %base case, if low and high are equal
range(Low, High, [H|T]):- %set the head of the list
    Low > High,
    !, fail; % force failure
    H is Low,
    Num is Low + 1, %increment low by 1
    range(Num, High, T).    %recursive call

, но это оставит бесполезную точку выбора для каждого вычисляемого элемента.

edit

Вотвозможность получить пустой список для ваших требований:

range(Low, High, R):-
    (   Low > High
    ->  R = []
    ;   R = [Low|T],
        Num is Low + 1,
        range(Num, High, T)
    ).

Примечание. Я удалил первое предложение (базовая рекурсия, теперь охватываемая первой ветвью) и использовал более простой для чтения ' if-тогда еще 1025 * построить.Для нашего фрагмента это эквивалентно следующему:

range(Low, High, R):-
    (   Low > High,
    !,  R = []
    ;   R = [Low|T],
        Num is Low + 1,
        range(Num, High, T)
    ).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...