Пролог Использование findall/3 на матрице

У меня есть следующая матрица в моем прологе SWI;

 matrix(1,[  [*,*,*,*,*,*,*,*,*,*,*,*],
        [*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],
        [*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],
        [*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],
        [*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],
        [*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],
        [*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],
        [*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],
        [*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],
        [*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*]
        [*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],
        [*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]]).

Я хочу использовать предикат findall/3, чтобы получить список всех фактов Spot(X,Y), таких как >>>

 findall(spots(X,Y),matrix(1,Map),X). 

Который должен вернуть что-то вроде следующего:

 X = (spots(2,4), spots(2,5), spots(2,10), spots(2,11), spots(3,4) etc .... spots(12,10)). 

Однако я очень запутался в том, как это реализовать, из-за того, что матрица состоит из списка в списке. Был бы признателен, если бы кто-нибудь мог показать мне настроенный предикат, чтобы получить список, как указано.

Спасибо за любую помощь!!! - действительно ценю это!

Редактировать — возможно, я смогу использовать этот код, приведенный ниже, и не смогу понять, как я могу реализовать его во втором операторе findall/3. Действительно застрял, так что буду признателен за любую помощь в этом.

at(Mat, Row, Col, Val) :- nth1(Row, Mat, ARow), nth1(Col, ARow, Val).

person Community    schedule 05.04.2016    source источник


Ответы (1)


Просто подумайте, что должен описывать ваш предикат: вы хотите найти все термины формы spots(_,_) в списке списков, который иначе состоит из атомов *.

:- use_module(library(lists)).

matrix_spots([],[]).                % no spots in the empty matrix
matrix_spots([R|Rs],S) :-
    row_spots(R,RSs),               % RSs ... spots in row R
    matrix_spots(Rs,S1),            % S1 ... spots in the remaining rows
    append(RSs,S1,S).               % S ... RSs followed by S1

row_spots([],[]).                   % no spots in an empty row
row_spots([E|Es],[E|RSs]) :-        % E is in the list of spots
    E=spots(_,_),                   % if it is a spot
    row_spots(Es,RSs).              % RSs ... spots in rest of row
row_spots([*|Es],RSs) :-            % * is not in the list of spots
    row_spots(Es,RSs).              % Rss ... spots in rest of row

Теперь вы можете запросить свою матрицу для всех ее точек:

   ?- matrix(1,M), matrix_spots(M,S).
M = [[*,*,*,*,*,*,*,*,*,*,*,*],[*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],[*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],[*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],[*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],[*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],[*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],[*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],[*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],[*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*],[*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],[*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]],
S = [spots(2,4),spots(2,5),spots(2,10),spots(2,11),spots(3,4),spots(3,5),spots(3,6),spots(3,7),spots(3,10),spots(3,11),spots(4,3),spots(4,4),spots(4,6),spots(4,7),spots(4,8),spots(4,9),spots(4,11),spots(4,12),spots(5,2),spots(5,3),spots(5,4),spots(5,5),spots(5,8),spots(5,9),spots(5,11),spots(5,12),spots(6,2),spots(6,3),spots(6,5),spots(6,6),spots(6,7),spots(6,8),spots(6,10),spots(6,11),spots(6,12),spots(7,3),spots(7,4),spots(7,6),spots(7,7),spots(7,8),spots(7,10),spots(7,11),spots(8,2),spots(8,3),spots(8,4),spots(8,6),spots(8,7),spots(8,8),spots(8,9),spots(8,11),spots(8,12),spots(9,2),spots(9,3),spots(9,5),spots(9,6),spots(9,9),spots(9,10),spots(9,11),spots(9,12),spots(10,2),spots(10,3),spots(10,5),spots(10,6),spots(10,7),spots(10,8),spots(10,10),spots(10,11),spots(11,3),spots(11,4),spots(11,7),spots(11,8),spots(11,9),spots(1ts(12,4),spots(12,9),spots(12,10)] ? ;
no

Обратите внимание, что у вас в матрице примера опечатка: в конце 10-го списка отсутствует запятая: ...spots(10,11),*],

Редактировать:

Вот версия dcg, предложенная @mat в комментариях. Это действительно намного легче читать:

matrix_spots(M,S) :-
    phrase(rows(M),S).

rows([]) -->                % no spots in the empty matrix
    [].
rows([R|Rs]) -->
    row(R),                 % all spots in row R
    rows(Rs).               % all spots in the remaining rows

row([]) -->                 % no spots in an empty row
    [].
row([*|Xs]) -->             % no spot at this position in the row
    row(Xs).                % but there might be in the remainder 
row([spots(A,B)|Xs]) -->    % spot at this position
    [spots(A,B)],           % is in the list
    row(Xs).                % and the spots in the rest of the row

Приведенный выше запрос можно использовать один к одному с этой версией dcg.

Относительно вашего вопроса findall/3 (@User15388472) в комментариях: представьте, что у вас есть предикат matrix_spot/2, который соответствует одному термину формы spots(A,B) в качестве второго аргумента вместо списка всех точек. Этот предикат может выглядеть примерно так:

matrix_spot([R|Rs],S) :-
    row_spot(R,S).                      % S is in row R
matrix_spot([R|Rs],S) :-                % S is not in R but
    matrix_spot(Rs,S).                  % in one of the other rows Rs

row_spot([spots(A,B)|Xs],spots(A,B)).   % head of the list is the spot
row_spot([X|Xs],S) :-
    row_spot(Xs,S).                     % S is in the tail of the list

Если вы запросите этот предикат, вы получите по одному spots(A,B) за раз в качестве ответа:

   ?- matrix(1,M), matrix_spot(M,S).
M = [[*,*,*,*,*,*,*,*,*,*,*,*],[*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],[*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],[*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],[*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],[*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],[*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],[*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],[*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],[*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*],[*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],[*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]],
S = spots(2,4) ? ;
M = [[*,*,*,*,*,*,*,*,*,*,*,*],[*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],[*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],[*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],[*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],[*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],[*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],[*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],[*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],[*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*],[*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],[*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]],
S = spots(2,5) ? ;
...

В таком сценарии вы можете использовать findall/3, чтобы найти все термины spots(A,B) в матрице:

   ?- matrix(1,M), findall(S,matrix_spot(M,S),Spots).
M = [[*,*,*,*,*,*,*,*,*,*,*,*],[*,*,*,spots(2,4),spots(2,5),*,*,*,*,spots(2,10),spots(2,11),*],[*,*,*,spots(3,4),spots(3,5),spots(3,6),spots(3,7),*,*,spots(3,10),spots(3,11),*],[*,*,spots(4,3),spots(4,4),*,spots(4,6),spots(4,7),spots(4,8),spots(4,9),*,spots(4,11),spots(4,12)],[*,spots(5,2),spots(5,3),spots(5,4),spots(5,5),*,*,spots(5,8),spots(5,9),*,spots(5,11),spots(5,12)],[*,spots(6,2),spots(6,3),*,spots(6,5),spots(6,6),spots(6,7),spots(6,8),*,spots(6,10),spots(6,11),spots(6,12)],[*,*,spots(7,3),spots(7,4),*,spots(7,6),spots(7,7),spots(7,8),*,spots(7,10),spots(7,11),*],[*,spots(8,2),spots(8,3),spots(8,4),*,spots(8,6),spots(8,7),spots(8,8),spots(8,9),*,spots(8,11),spots(8,12)],[*,spots(9,2),spots(9,3),*,spots(9,5),spots(9,6),*,*,spots(9,9),spots(9,10),spots(9,11),spots(9,12)],[*,spots(10,2),spots(10,3),*,spots(10,5),spots(10,6),spots(10,7),spots(10,8),*,spots(10,10),spots(10,11),*],[*,*,spots(11,3),spots(11,4),*,*,spots(11,7),spots(11,8),spots(11,9),spots(11,10),*,*],[*,*,spots(12,3),spots(12,4),*,*,*,*,spots(12,9),spots(12,10),*,*]],
Spots = [spots(2,4),spots(2,5),spots(2,10),spots(2,11),spots(3,4),spots(3,5),spots(3,6),spots(3,7),spots(3,10),spots(3,11),spots(4,3),spots(4,4),spots(4,6),spots(4,7),spots(4,8),spots(4,9),spots(4,11),spots(4,12),spots(5,2),spots(5,3),spots(5,4),spots(5,5),spots(5,8),spots(5,9),spots(5,11),spots(5,12),spots(6,2),spots(6,3),spots(6,5),spots(6,6),spots(6,7),spots(6,8),spots(6,10),spots(6,11),spots(6,12),spots(7,3),spots(7,4),spots(7,6),spots(7,7),spots(7,8),spots(7,10),spots(7,11),spots(8,2),spots(8,3),spots(8,4),spots(8,6),spots(8,7),spots(8,8),spots(8,9),spots(8,11),spots(8,12),spots(9,2),spots(9,3),spots(9,5),spots(9,6),spots(9,9),spots(9,10),spots(9,11),spots(9,12),spots(10,2),spots(10,3),spots(10,5),spots(10,6),spots(10,7),spots(10,8),spots(10,10),spots(10,11),spots(11,3),spots(11,4),spots(11,7),spots(11,8),spots(11,9),spots(11,10),spots(12,3),spots(12,4),spots(12,9),spots(12,10)]
person tas    schedule 05.04.2016
comment
спасибо за это @tas ... действительно полезно. Для моей собственной выгоды можно ли использовать предикат findall/3 для получения тех же результатов? - person ; 05.04.2016
comment
@mat: Конечно, ты абсолютно прав. Я добавил версию DCG выше - person tas; 06.04.2016
comment
@ User15388472: Я добавил еще одну версию, которая, надеюсь, ответит на ваш вопрос относительно findall/3. - person tas; 06.04.2016