我正在尝试创建一个谓词,它返回包含我给出的某个数字的列表元素。
示例:
?- where_is_it( [ [1,2,3] , [1,2,7] , [4,5] , [8] ] , 7 , X ).
X=[1,2,7].
我是一个相对较新的prolog程序员,所以这是我的代码:
where_is_it([],_,[]).
where_is_it([H|T],Num,H):-
member([Num],H),!,
where_is_it(T,Num,[]).
非常感谢
答案 0 :(得分:6)
where_is_it(Xss, X, Xs) :-
member(Xs, Xss),
member(X, Xs).
答案 1 :(得分:6)
您可以使用模块reif中的if_/3
和memberd_t/2
,以便更具确定性:
where_is_it([H|T], X, L) :-
if_(memberd_t(X,H), L=H, where_is_it(T, X, L)).
答案 2 :(得分:5)
以下是使用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).
答案 3 :(得分:4)
这是仅使用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
同一个列表的多次出现只匹配一次(与带有member / 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
最常见的查询(与包含member / 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
答案 4 :(得分:3)
您应该阅读您的条款所说的内容吗?你可能需要一个句子,“如果X是H的成员,那么H就是解决方案”:
where_is_it([H|_], X, H) :-
member(X, H).
然后你仍然需要另一个条款,说明你可能在列表的其余部分有一个解决方案:
where_is_it([_|T], X, H) :-
where_is_it(T, X, H).
也许这足以开始?
答案 5 :(得分:2)
好的,让我们来看看你的代码。第一个条款很好,无论我们在寻找什么,它都不在空列表中。
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).
答案 6 :(得分:0)
我没有看到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解决方案:
/* 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解决方案:
/* 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解决方案是ca. 18次,约相应的3倍慢2倍。