我正在尝试创建一个规则F(C,L)
,其中C
和L
是整数列表。 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)
).
答案 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保留了logical-purity,但它在以下查询中显示效率低下:
?- list_contains_at1s([43,42,43,42,42,43], 43, Ps). Ps = [1,3,6] ; % <------ SWI toplevel indicates lingering choicepoint false.
在上面的查询中,保证延迟的选择点是无用的:我们知道上面的用例永远不会产生多个解决方案。
earlier definition of list_contains_at_index1/4
有两个递归条款 - 一个覆盖“相等”案例,另一个覆盖“不相等”案例。
请注意,list_contains_at_index1/4
的这两个递归子句是互斥的,因为(=)/2
和dif/2
是互斥的。
我们如何利用这个?
将 first-argument indexing与reified 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
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].
...我们看到现在的查询确定性地成功。任务完成了!