Ваш 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
...