Prolog:添加到列表中具有特定属性的另一个列表的所有成员

时间:2016-07-02 17:38:07

标签: list prolog

我正在尝试创建一个规则F(C,L),其中CL是整数列表。 L包含C所有等于43的元素的索引号(从1开始)。我的代码如下所示。当我尝试F([43,42,43,42,42,43],L)时。它返回true。我做错了什么?提前谢谢!

F(C,L) :-
    forall(
        (
            member(X,C),
            X=43,
            nth1(N,C,X)
        ),
        member(N,L)
    ).

4 个答案:

答案 0 :(得分:3)

code by @CapelliC 有效,但与充分实例化一起使用

?- f([43,42,43,42,42,43], Ps).
Ps = [1,3,6].                              % ok

?- f([A,B], Ps).
Ps = [1,2].                                % BAD

?- f(_, _).
**LOOPS**                                  % BAD: doesn't terminate

为了防范我们可以使用的问题 iwhen/2喜欢这样:

f_safe(C, L) :-
   iwhen(ground(C), findall(X,nth1(X,C,43),L)).

让我们使用SWI-Prolog重新运行查询:

?- f_safe([43,42,43,42,42,43], Ps).
Ps = [1,3,6].                              % still ok

?- f_safe([A,B], Ps).                      % BETTER
ERROR: Arguments are not sufficiently instantiated

?- f_safe(_, _).                           % BETTER
ERROR: Arguments are not sufficiently instantiated

答案 1 :(得分:2)

语法错误分开,你做的比你需要的更复杂。保持简单,并使用findall / 3而不是forall / 2。后者不能用于实例化范围之外的变量。

f(C,L) :- findall(X, nth1(X,C,43), L).

答案 2 :(得分:2)

一步一步地采取行动:

:- use_module(library(clpfd)).

list_contains_at1s(Elements, Member, Positions) :-
   list_contains_at_index1(Elements, Member, Positions, 1).

list_contains_at_index1([], _, [], _).
list_contains_at_index1([E|Es], E, [I1|Is], I1) :-
   I2 #= I1+1,
   list_contains_at_index1(Es, E, Is, I2).
list_contains_at_index1([E|Es], X, Is, I1) :-
   dif(X, E),
   I2 #= I1+1,
   list_contains_at_index1(Es, X, Is, I2).

使用SWI-Prolog进行示例查询:

?- list_contains_at1s([43,42,43,42,42,43], 43, Positions).
   Positions = [1,3,6]
;  false.                                % left-over choicepoint

答案 3 :(得分:2)

虽然this previous answer保留了,但它在以下查询中显示效率低下:

?- list_contains_at1s([43,42,43,42,42,43], 43, Ps).
Ps = [1,3,6] ;       % <------ SWI toplevel indicates lingering choicepoint
false.

在上面的查询中,保证延迟的选择点是无用的:我们知道上面的用例永远不会产生多个解决方案。

方法1:显式索引和额外帮助谓词

earlier definition of list_contains_at_index1/4两个递归条款 - 一个覆盖“相等”案例,另一个覆盖“不相等”案例。

请注意,list_contains_at_index1/4的这两个递归子句是互斥的,因为(=)/2dif/2是互斥的。

我们如何利用这个?

first-argument indexingreified term equality predicate (=)/3一起使用!

:- use_module(library(reif)).

list_contains_at_index1([], _, [], _).
list_contains_at_index1([E|Es], X, Is0, I1) :-
   =(E, X, T),                              % (=)/3
   equal_here_at0_at(T, I1, Is0, Is),
   I2 #= I1+1,
   list_contains_at_index1(Es, X, Is, I2).

equal_here_at0_at(true , I1, [I1|Is], Is).  % index on the truth value ...
equal_here_at0_at(false,  _,     Is , Is).  % ... of reified term equality

方法2:使用if_/3

进行隐式索引,无额外辅助谓词

对于更简洁的代码,我们可以很好地使用if_/3

list_contains_at_index1([], _, [], _).
list_contains_at_index1([E|Es], X, Is0, I1) :-
   if_(E = X, Is0 = [I1|Is], Is0 = Is),
   I2 #= I1+1,
   list_contains_at_index1(Es, X, Is, I2).

如果我们使用新改进的代码重新运行上述查询...

?-  list_contains_at1s([43,42,43,42,42,43], 43, Positions).
Positions = [1, 3, 6].

...我们看到现在的查询确定性地成功。任务完成了!