在 Prolog 中复制 findall

Replicating findall in Prolog

我正在尝试使用一些代码来 return 一个 positions/indices 的单个列表,其中的元素位于某些基本列表中。经过多次搜索、复制、调整等。以下代码是我到目前为止所得到的。

它在 SWISH 中有效,但需要我多次点击下一步才能最终获得包含所搜索元素的所有位置的单个列表。

我如何让它在 sending/printing 返回结果列表之前完成所有答案?

pos([E|_],E,I,P) :-  P = I.
pos([E|T],E,I,[P|Pt]) :- I1 is I+1, pos(T,E,I1,Pr), Pt = Pr, P = I.
pos([H|T],E,I,P) :- H\=E, I1 is I+1, pos(T,E,I1,Pr), P = Pr.

find(X,P):- a(L),pos(L,X,1,Pr), P = Pr.

a([2,1,4,5,3,2,6,2,1,21,2,1,4,7,4,3,5,2,4,6,8,2,1,37,3,2]).

结果:

?- find(2,X)
X = 1
X = [1|6]
X = [1, 6|8]
X = [1, 6, 8|11]
X = [1, 6, 8, 11|18]
X = [1, 6, 8, 11, 18|22]
X = [1, 6, 8, 11, 18, 22|26]

有几种可能的解决方案。 如果你想保留你的代码,你应该这样写(基本上,你确实需要在找到匹配时再次调用谓词)

find_in([],_,_,[]).
find_in([El|TL],El,Pos,[Pos|T]):- !,
    P1 is Pos + 1,
    find_in(TL,El,P1,T).
find_in([_|T],El,Pos,L):-
    P1 is Pos + 1,
    find_in(T,El,P1,L).

find_pos(El,LPos):-
    a(L),
    find_in(L,El,1,LPos).

?- find_pos(2,X).
X = [1, 6, 8, 11, 18, 22, 26]

我已经使用了剪切,但您可以使用 \= 避免它(就像您在问题中所做的那样)。 如果您可以使用内置谓词(nth0/3 或类似的东西和 findall/3),则有一个更紧凑的解决方案:

find_pos(El,LPos):-
    a(L),
    findall(I,nth1(I,L,El),LPos).

?- find_pos(2,X).
X = [1, 6, 8, 11, 18, 22, 26]