我刚刚编写了一个程序,执行以下任务:"获取元素,其值等于其索引"。
以下是代码:
% get element's index
get_index([Element|_], Element, 0).
get_index([_|T], Element, Index) :-
get_index(T, Element, Index1),
Index is Index1+1.
index_equals_to_element(List, List2) :-
member(X, List),
get_index(List, X, Index),
Index =:= X,
append([], [X], List2).
效果很好。但是有一个问题。对于列表 [0,3,2,4,0] ,我的谓词index_equals_to_element
会返回 [0,2,0] 。
好的,让它发生。但是,当我尝试仅输出唯一元素时,我会在没有任何更改的情况下获得相同的列表。例如:
?- index_equals_to_element([0, 3, 2, 4, 0], List).
% Outputs [0, 2, 0]
?- sort(List, List2).
% Outputs [0, 2, 0] either, when expected [0, 2]
对我来说这很奇怪,因为这很好用:
?- sort([0, 2, 1, 0], List).
% Outputs [0, 1, 2].
为什么sort
不能仅使用我的谓词生成的列表?
答案 0 :(得分:4)
一个简单的解决方案是:
index_equals_to_element(List1, List2) :-
% assume that list position index starts at 0
index_equals_to_element(List1, 0, List2).
index_equals_to_element([], _, []).
index_equals_to_element([X| Xs], Index, List2) :-
NextIndex is Index + 1,
( X == Index ->
List2 = [X| Tail],
index_equals_to_element(Xs, NextIndex, Tail)
; index_equals_to_element(Xs, NextIndex, List2)
).
示例电话:
?- index_equals_to_element([0, 3, 2, 4, 0], List).
List = [0, 2].
我建议您通过输入查询来使用Prolog系统的跟踪功能来研究它:
?- trace, index_equals_to_element([0, 3, 2, 4, 0], List).
执行步骤,直到您明确谓词定义。
答案 1 :(得分:3)
您的index_equals_to_element([0, 3, 2, 4, 0], List).
未按照您的要求输出[0, 2, 0]
,但会给出三个答案[0]
,[2]
和[0]
:
?- index_equals_to_element([0, 3, 2, 4, 0], List).
List = [0] ;
List = [2] ;
List = [0] ;
false.
您可以使用findall
来获得所需内容:
?- findall(X, index_equals_to_element([0, 3, 2, 4, 0], [X]), List).
List = [0, 2, 0].
更新。以下是我认为index_equals_to_element/2
更好的实施方式:
index_equals_to_element(List, List2) :-
index_equals_to_element(List, 0, List2).
index_equals_to_element([], _, []).
index_equals_to_element([X | Rest], I, Rest2) :-
Inext is I + 1,
index_equals_to_element(Rest, Inext, NewRest),
( X =:= I ->
Rest2 = [X | NewRest]
;
Rest2 = NewRest
).
试运行:
?- index_equals_to_element([0, 3, 2, 4, 0], List).
List = [0, 2].
?- index_equals_to_element([0, 1, 2, 2, 4, 5], List).
List = [0, 1, 2, 4, 5].
答案 2 :(得分:2)
其他答案最适合学习Prolog的基本要点。但是,使用SWI-Prolog findall/3
中的高阶谓词nth0/3
和library(lists)
,这是一个更简洁(但也更容易理解)的解决方案:
elements_equal_to_index(List, Elements) :-
findall(Index, nth0(Index, List, Index), Elements).
修改强>
正如@Paulo Moura在评论中所指出的,如果所有参数都被实例化,上述答案仅相当于此处提供的其他答案。即,如果上面遇到列表中的自由变量,我会将该变量绑定到列表中的索引,而不是将其拒绝为不满意的元素。为索引和列表元素之间的强相等性添加测试应该使答案符合:
elements_equal_to_index(List, Elements) :-
findall( Index,
( nth0(Index, List, Elem),
Elem == Index ),
Elements
).