Мы можем определить этот предикат с помощью индуктивного определения. A Subgroup
является подгруппой Group
, если:
-
Subgroup
- пустой список;
- первый элемент
Subgroup
совпадает с первым элементом Group
, а остальная часть Subgroup
является подгруппой остальных элементов Group
;
-
Subgroup
является подгруппой остальных Group
.
Нам необходимо соответственно обновить N
, чтобы, если Subgroup
пуст, то длина была 0
:
isSubgroup([], _, 0). %% (1)
isSubgroup([H|TS], [H|TG], N) :- %% (2)
N1 is N-1,
isSubgroup(TS, TG, N1).
isSubgroup(S, [_|TG], N) :- %% (3)
isSubgroup(S, TG, N).
Приведенное выше, однако, приводит к двойным истинам для той же подгруппы . Это связано с тем, что мы можем удовлетворить предикат несколькими способами. Например, если мы позвоним:
isSubgroup([], [1,2], 0).
тогда оно удовлетворяется посредством факта (1), но последний пункт (3) также вызывает это с помощью isSubgroup([], [1], 0).
, который затем будет удовлетворен посредством факта (1) и т. Д.
Мы можем избежать этого, сделав последнее предложение более ограничительным:
isSubgroup([], _, 0). %% (1)
isSubgroup([H|TS], [H|TG], N) :- %% (2)
N1 is N-1,
isSubgroup(TS, TG, N1).
isSubgroup([HS|TS], [_|TG], N) :- %% (3)
isSubgroup([HS|TS], TG, N).
Вышеуказанное работает для данных «направлений» (все аргументы должны быть обоснованы, являются «входными»). Но обычно каждый хочет использовать предикат и в других направлениях. Мы можем реализовать версию, которая работает в основном, когда мы используем аргументы в качестве «вывода», и при этом все еще используем оптимизацию хвостового вызова (TCO) :
isSubgroup(S, G, N) :-
isSubgroup(S, G, 0, N).
isSubgroup([], _, L, L). %% (1)
isSubgroup([H|TS], [H|TG], L, N) :- %% (2)
L1 is L+1,
isSubgroup(TS, TG, L1, N).
isSubgroup([HS|TS], [_|TG], L, N) :- %% (3)
isSubgroup([HS|TS], TG, L, N).
Например:
?- isSubgroup([1,4,2], G, N).
G = [1, 4, 2|_2974],
N = 3 ;
G = [1, 4, _2972, 2|_2986],
N = 3 ;
G = [1, 4, _2972, _2984, 2|_2998],
N = 3 ;
G = [1, 4, _2972, _2984, _2996, 2|_3010],
N = 3 .
Здесь Пролог, таким образом, может предлагать группы, для которых [1,4,2]
является подгруппой, и он способен определять длину N
подгруппы.
Мы можем запросить и в обратном направлении:
?- isSubgroup(S, [1,4,2], N).
S = [],
N = 0 ;
S = [1],
N = 1 ;
S = [1, 4],
N = 2 ;
S = [1, 4, 2],
N = 3 ;
S = [1, 2],
N = 2 ;
S = [4],
N = 1 ;
S = [4, 2],
N = 2 ;
S = [2],
N = 1 ;
false.
Пролог может для данной группы [1,4,2]
исчерпывающе перечислить все возможные подгруппы вместе с N
длиной этой подгруппы.