Ответ 1
where_is_it(Xss, X, Xs) :-
member(Xs, Xss),
member(X, Xs).
Я пытаюсь создать предикат, который возвращает мне элемент списка, который содержит определенное число, указанное мной.
Пример:
?- where_is_it( [ [1,2,3] , [1,2,7] , [4,5] , [8] ] , 7 , X ).
X=[1,2,7].
Я - относительно новый пролог-программист, так что это мой код:
where_is_it([],_,[]).
where_is_it([H|T],Num,H):-
member([Num],H),!,
where_is_it(T,Num,[]).
Большое спасибо
where_is_it(Xss, X, Xs) :-
member(Xs, Xss),
member(X, Xs).
Вы можете использовать if_/3
и memberd_t/2
из модуля reif, чтобы быть более детерминированным:
where_is_it([H|T], X, L) :-
if_(memberd_t(X,H), L=H, where_is_it(T, X, L)).
Вот реализация с использованием tmember/2
:
where_is_it(InList, X, L):- tmember(check(X,L),InList).
check(X,L,L1,T):- if_( memberd_t(X,L1), (T = true, L = L1), T = false).
Вот версия, использующая только tmember/2 и (=)/3 без какой-либо явной рекурсии
where_is_it(Xss,X,Xs) :-
tmember(=(Xs),Xss),
tmember(=(X),Xs).
Запрос, заданный OP, работает как ожидалось:
?- where_is_it([[1,2,3],[1,2,7],[4,5],[8]],7,X).
X = [1,2,7] ? ;
no
Некоторые функции этой версии: Если элемент встречается в нескольких списках (отличается от версии с if_/3 и memberd_t):
?- where_is_it([[1,2,3],[1,2,7],[4,5],[8]],1,X).
X = [1,2,3] ? ;
X = [1,2,7] ? ;
no
Несколько вхождений элемента в один список сопоставляются только один раз (отличается от версии с элементом /2):
?- where_is_it([[1,2,3,1],[4,5],[8]],1,X).
X = [1,2,3,1] ? ;
no
Несколько вхождений одного и того же списка сопоставляются только один раз (отличается от версии с элементом /2):
?- where_is_it([[1,2,3],[1,2,3],[4,5],[8]],1,X).
X = [1,2,3] ? ;
no
Даже с открытым списком (отличается от версии с членом /2, а также с версией if_/3 и memberd_t):
?- where_is_it([[1,2,3],[1,2,7],[4,5],[8],[1|_]],1,X).
X = [1,2,3] ? ;
X = [1,2,7] ? ;
X = [1|_A],
dif([1|_A],[1,2,3]),
dif([1|_A],[1,2,7]) ? ;
no
Если фактический элемент является переменным:
?- where_is_it([[1,2,3],[8]],Y,X).
X = [1,2,3],
Y = 1 ? ;
X = [1,2,3],
Y = 2 ? ;
X = [1,2,3],
Y = 3 ? ;
X = [8],
Y = 8 ? ;
no
Самый общий запрос (отличается от версии с членом /2 (только немного), а также с версией if_/3 и memberd_t):
?- where_is_it(Xss,X,Xs).
Xs = [X|_A],
Xss = [[X|_A]|_B] ? ;
Xs = [_A,X|_B],
Xss = [[_A,X|_B]|_C],
dif(X,_A) ? ;
Xs = [_A,_B,X|_C],
Xss = [[_A,_B,X|_C]|_D],
dif(X,_B),
dif(X,_A) ? ;
...
С некоторыми ограничениями (отличается от версии с членом /2 (только слегка), а также с версией if_/3 и memberd_t):
?- Xss=[_,_],Xs=[_,_],where_is_it(Xss,X,Xs).
Xs = [X,_A],
Xss = [[X,_A],_B] ? ;
Xs = [_A,X],
Xss = [[_A,X],_B],
dif(X,_A) ? ;
Xs = [X,_A],
Xss = [_B,[X,_A]],
dif([X,_A],_B) ? ;
Xs = [_A,X],
Xss = [_B,[_A,X]],
dif(X,_A) ? ;
no
Вы должны, возможно, прочитать, что говорят ваши предложения? Вам нужно, может быть, одно предложение, которое гласит: "Если X является членом H, то H является решением":
where_is_it([H|_], X, H) :-
member(X, H).
а затем вам еще нужно другое предложение, в котором говорится, что, возможно, у вас есть решение в остальной части списка:
where_is_it([_|T], X, H) :-
where_is_it(T, X, H).
Может быть, этого достаточно для начала?
Хорошо, давайте посмотрим на ваш код. Первое предложение прекрасно, все, что мы ищем, не находится в пустом списке.
where_is_it([],_,[]).
Это ваше второе предложение:
where_is_it([H|T],Num,H):-
member([Num],H),!,
where_is_it(T,Num,[]).
Здесь у нас есть несколько проблем:
Во-первых, вместо member([Num],H)
вам, вероятно, понадобится member(Num,H)
, выражая, что Num является элементом списка H.
Во-вторых, если это предложение для случаев, когда Num является членом H, ваша рекурсия должна быть следующей:
where_is_it([H|T],Num,[H|Found]):-
member(Num,H),!,
where_is_it(T,Num,Found).
Теперь этот пункт выражает, что всякий раз, когда Num является членом H, H принадлежит к нашему списку решений, и мы должны искать дальнейшие решения в хвосте нашего списка (то есть в T) и собирать их в Found.
Вам понадобится дополнительное предложение для случая, когда Num не является членом H:
where_is_it([H|T],Num,Found):-
where_is_it(T,Num,Found).
Этот раздел не изменяет список найденных решений.
Следовательно, полный код:
where_is_it([],_,[]).
where_is_it([H|T],Num,[H|Found]):-
member(Num,H),!,
where_is_it(T,Num,Found).
where_is_it([_H|T],Num,Found):-
where_is_it(T,Num,Found).
Я не вижу никакого преимущества reif, за исключением замедления:-(, возьмите эти решения:
Традиционные решения:
/* variant 1 */
where_is_it(Xss, X, Xs) :-
member(Xs, Xss),
member(X, Xs).
/* variant 2 */
where_is_it2(Xss, X, Xs) :-
member(Xs, Xss),
memberchk(X, Xs), !.
/* variant 3 */
where_is_it3([H|T], X, R) :-
(memberchk(X, H) -> R=H; where_is_it3(T, X, R)).
reif solutions:
/* variant 1 */
where_is_it(Xss, X, Xs) :-
tmember(=(Xs), Xss),
tmember(=(X), Xs).
/* variant 2 */
where_is_it2(InList, X, L):-
tmember(check(X,L),InList).
check(X,L,L1,T):-
if_( memberd_t(X,L1), (T = true, L = L1), T = false).
/* variant 3 */
where_is_it3([H|T], X, L) :-
if_(memberd_t(X,H), L=H, where_is_it3(T, X, L)).
Тайминги выглядят следующим образом:
Традиционное решение:
/* variant 1 */
?- where_is_it([[4,5],[1,2,3],[8],[1,2,7]],1,X).
X = [1, 2, 3] ;
X = [1, 2, 7] ;
false.
/* variant 2 */
?- where_is_it2([[4,5],[1,2,3],[8],[1,2,7]],1,X).
X = [1, 2, 3].
/* variant 3 */
?- where_is_it3([[4,5],[1,2,3],[8],[1,2,7]],1,X).
X = [1, 2, 3].
/* variant 1 */
?- time((between(1,1_000_000,_),
where_is_it([[4,5],[1,2,3],[8],[1,2,7]],1,_),
fail; true)).
% 20,000,001 inferences, 1.031 CPU in 1.031 seconds (100% CPU, 19393940 Lips)
true.
/* variant 2 */
?- time((between(1,1_000_000,_),
where_is_it2([[4,5],[1,2,3],[8],[1,2,7]],1,_),
fail; true)).
% 7,000,000 inferences, 0.422 CPU in 0.422 seconds (100% CPU, 16592593 Lips)
true.
/* variant 3 */
time((between(1,1_000_000,_),
where_is_it3([[4,5],[1,2,3],[8],[1,2,7]],1,_),
fail; true)).
% 6,000,000 inferences, 0.297 CPU in 0.297 seconds (100% CPU, 20210526 Lips)
true.
reif solution:
/* variant 1 */
?- where_is_it([[4,5],[1,2,3],[8],[1,2,7]],1,X).
X = [1, 2, 3] ;
X = [1, 2, 7] ;
false.
/* variant 2 */
?- where_is_it2([[4,5],[1,2,3],[8],[1,2,7]],1,X).
X = [1, 2, 3].
/* variant 3 */
?- where_is_it3([[4,5],[1,2,3],[8],[1,2,7]],1,X).
X = [1, 2, 3].
/* variant 1 */
?- time((between(1,1_000_000,_),
where_is_it([[4,5],[1,2,3],[8],[1,2,7]],1,_),
fail; true)).
% 400,000,001 inferences, 18.688 CPU in 18.674 seconds (100% CPU, 21404682 Lips)
true.
/* variant 2 */
?- time((between(1,1_000_000,_),
where_is_it2([[4,5],[1,2,3],[8],[1,2,7]],1,_),
fail; true)).
% 18,000,000 inferences, 1.203 CPU in 1.203 seconds (100% CPU, 14961039 Lips)
true.
/* variant 3 */
?- time((between(1,1_000_000,_),
where_is_it3([[4,5],[1,2,3],[8],[1,2,7]],1,_),
fail; true)).
% 13,000,000 inferences, 0.688 CPU in 0.687 seconds (100% CPU, 18909091 Lips)
true.
В основном решение reif составляет ок. 18 раз, ок. 3-кратный соответствующий ок. В 2 раза медленнее.