Пролог. После присвоения переменной значения, выход программы изменяется с `yes` на` no` - PullRequest
1 голос
/ 15 марта 2020

У меня есть простая задача найти положение массива в другом массиве. Кстати, я использую GNU Prolog 1.4.5.

parse([], _) :- true. %parsed sub means that we found it
parse([SHead|STail], [Head|Tail]) :-
    write(SHead), write(' '), write(STail), write(' | '), write(Head), write(' '), write(Tail), nl,
    (
        SHead =:= Head -> 
            parse(STail, Tail) 
        ;
            false
    )
.

findsub([_|_], [], _) :- false. %unparsed sub & empty string means there is no sub
findsub([SHead|STail], [Head|Tail], Pos) :-
    (
        var(Pos) -> Pos = 0 ; true %first-time init
    ),
    XPos is Pos + 1,
    (
        SHead =:= Head ->
            (
                parse(STail, Tail) ->
                    true %subarray found
                ;
                    findsub([SHead|STail], Tail, XPos) %continue to next el
            )
        ;
            findsub([SHead|STail], Tail, XPos)
    )
.

Программа работает правильно, но я не могу найти способ правильно установить значение переменной Pos, чтобы она возвращала фактическую позицию. Добавление Pos is XPos, после parse(STail, Tail) -> изменяет поведение программы на неправильное. Не понимаю почему. Данные для теста: findsub("a", "sdfsfgasfdsfsdf", Pos).

1 Ответ

0 голосов
/ 15 марта 2020

Обратите внимание, что в Прологе нет операции присваивания (как в процедурных языках). Оператор =/0 используется для объединения терминов .

. Рассматривая ваш код, мы можем начать с упрощения предиката parse/2:

parse([], _). %parsed sub means that we found it
parse([SHead|STail], [Head|Tail]) :-
    write(SHead), write(' '), write(STail), write(' | '),
    write(Head), write(' '), write(Tail), nl,
    SHead =:= Head, 
    parse(STail, Tail).

Для вашего Предикат findsub/3, вам нужно будет использовать аккумулятор , то есть вспомогательный аргумент для переноса текущей позиции, увеличивая ее при выполнении рекурсивного вызова:

findsub(SList, List, Position) :-
    findsub(SList, List, 1, Position).

findsub([_|_], [], _, _) :-
    % unparsed sub & empty string means there is no sub
    false.
findsub([SHead|STail], [Head|Tail], Position0, Position) :-
    (   SHead =:= Head ->
        (   parse(STail, Tail) ->
            % subarray found
            Position = Position0
        ;   % continue to next element
            Position1 is Position0 + 1,
            findsub([SHead|STail], Tail, Position1, Position)
        )
    ;   Position1 is Position0 + 1,
        findsub([SHead|STail], Tail, Position1, Position)
    ).

Ваш пример вызова:

| ?- findsub("a", "sdfsfgasfdsfsdf", Pos).

Pos = 7
yes
...