Проверьте, равен ли элемент в списке списков прологу - PullRequest
3 голосов
/ 02 июля 2019

Я пытаюсь проверить, равен ли весь список в списке списков длине списка списков.

Например, если у меня [[1,2], [3,4]] верно, потому что у меня есть 2 списка из 2 элементов.

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

[[1], [2,3]] ложно, потому что есть 2 списка, но не весь список имеет 2 элементы

[[1,2], [2,3], [3,4]] ложно, потому что у меня есть 2 списка, и у всех списков есть 2 элемента вместо двух

.

Я сделал эти две функции:

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

ma([],0).
ma([H|T],N):- count(H,M1),ma(T,N1), M1 is N1.

Я "посчитал" (и работал) для элемента count в списке и возвратил N количество элементов в списке.

Функция «ma» не работает, потому что «count» выполняется до 0, и возвращает 2, после выполнения ma, но до 1 шага, и после непосредственного выполнения M1 равно N1 и, очевидно, возвращает false. Я хочу сделать M1 N1 в конце программы (как и в другом языке программирования, но я думаю, что тогда это неправильная форма.

EDIT:

Даниил предлагает использовать:

ma([H],   N) :- length(H, N).
ma([H|T], N) :- length(H, N), ma(T, N).

Но список из 3 подсписков, все с 2 элементами, дает результат 2, вместо этого результат будет ложным (ошибка), потому что номер N в списке должен быть равен количеству элементов во ВСЕМ подсписке.

Я сделаю сам, без встроенного предиката пролога.

Ответы [ 2 ]

1 голос
/ 03 июля 2019

Здесь очень базовое решение без встроенных предикатов:

count_elements([],N,N).
count_elements([_|T],N,N0):-
    N1 is N+1,
    count_elements(T,N1,N0).

count_length_sub([],_).
count_length_sub([H|T],N):-
    count_elements(H,0,N),
    count_length_sub(T,N).

solve(L):-
    count_elements(L,0,NO),
    count_length_sub(L,NO).

?- solve([[1,2],[3,4]]).
true.

?- solve([[1,2],[2,3],[3,4]]).
false.
1 голос
/ 02 июля 2019

Ваш count/2 похож на встроенный length/2, за исключением того, что встроенный имеет больше шаблонов создания экземпляров (попробуйте length(X, Y) и посмотрите).Предпочитайте length/2.

Вы правы, что ваш предикат ma/2 бесполезен, поскольку 0 не является длиной подсписка.По сути, вы выбрали неправильный базовый вариант здесь;ваш базовый случай должен быть списком с ровно одним элементом в нем:

ma_1([H],   N) :- length(H, N).
ma_1([H|T], N) :- length(H, N), ma(T, N).

Вам нужно будет обернуть его во что-то, что гарантирует, что длина соответствует длине внешнего списка:

ma(L, N) :- length(L, N), ma_1(L, N).

Обратите внимание, что нет необходимости получать отдельные переменные и утверждать их равенство (ваш танец с N и N1).Пролог просто потерпит неудачу, что вам и нужно, если N не имеет правильного значения.(Примечание: не используйте is для объединения. Цель is - уменьшить арифметическое выражение с правой стороны до значения и присвоить его переменной слева, например, X is 2 + 3*4.)

Другим подходом было бы написать ваш фактический запрос в логической форме и записать его вместо этого.Логической формой этого запроса будет что-то вроде «ma (L, N), если N - это длина L, а для всех элементов X из L они также являются списками длины N».Это выглядит так:

ma(L, N) :- 
    length(L, N), 
    forall(member(X, L), 
           length(X, N)).

Это имеет преимущество в том, что не остается лишних точек выбора, хотя беспокоиться об этом обычно преждевременно.

Другой подход заключается в использовании maplist/N, что дает преимущество в том, что он возвращает вам списки с переменными.К сожалению, length/2 имеет свои параметры в неправильном порядке, поэтому вы не можете сделать действительно милую вещь и просто написать maplist(length(2), L).Тем не менее, вы можете сделать предикат flip/3, который переворачивает аргументы:

flip(P, Y, X) :- call(P, X, Y).

ma(L, N) :- length(L, N), maplist(flip(length, N), L).

Или вы можете импортировать library(yall) и использовать его лямбда-выражения:

ma(L, N) :- length(L, N), maplist({N}/[X]>>length(X, N), L).

Оба изэти подходы позволяют такие решения:

?- ma(X, N).
X = [],
N = 0 ;

X = [[_1976]],
N = 1 ;

X = [[_1982, _1988], [_1994, _2000]],
N = 2 ;

X = [[_1988, _1994, _2000], [_2006, _2012, _2018], [_2024, _2030, _2036]],
N = 3 
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...