SWI Prolog排序谓词不工作

SWI Prolog排序谓词不工作,prolog,Prolog,我刚刚编写了一个程序,执行以下任务:“获取元素,哪些值等于它们的索引” 代码如下: % 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, L

我刚刚编写了一个程序,执行以下任务:“获取元素,哪些值等于它们的索引”

代码如下:

% 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]我的谓词
索引元素
返回[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,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_=u 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].

您的
索引\u等于\u元素([0,3,2,4,0],列表)。
不会像您声称的那样输出
[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_=u 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].
一个简单的解决方案是:

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).
执行一步,直到谓词定义对您来说是清楚的。

一个简单的解决方案是:

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).

逐步执行,直到谓词定义对您来说是清楚的。

其他答案最适合学习Prolog的细节。但这里有一个更简洁(但也更容易探索)的解决方案,它使用SWI Prolog库(列表)中的高阶谓词
findall/3
nth0/3

编辑:

正如@Paulo Moura在一篇评论中指出的,如果所有参数都被实例化,则上述答案仅与此处提供的其他答案等效。也就是说,如果上面的内容在列表中遇到一个自由变量,我将把该变量绑定到列表中的索引,而不是作为不满意的元素拒绝它。添加索引和列表元素之间的强相等性测试应使答案符合:

elements_equal_to_index(List, Elements) :-
    findall( Index,
             ( nth0(Index, List, Elem),
               Elem == Index ),
             Elements
           ).

其他答案最适合学习Prolog的细节。但这里有一个更简洁(但也更容易探索)的解决方案,它使用SWI Prolog库(列表)中的高阶谓词
findall/3
nth0/3

编辑:

正如@Paulo Moura在一篇评论中指出的,如果所有参数都被实例化,则上述答案仅与此处提供的其他答案等效。也就是说,如果上面的内容在列表中遇到一个自由变量,我将把该变量绑定到列表中的索引,而不是作为不满意的元素拒绝它。添加索引和列表元素之间的强相等性测试应使答案符合:

elements_equal_to_index(List, Elements) :-
    findall( Index,
             ( nth0(Index, List, Elem),
               Elem == Index ),
             Elements
           ).

调用
append/3
是毫无意义的。将空列表与任何列表一起追加会导致相同的列表。也就是说,
append([],List,List)
总是正确的,假设
append/3
谓词的通用定义。调用
append/3
是毫无意义的。将空列表与任何列表一起追加会导致相同的列表。也就是说,
append([],List,List)
假设
append/3
谓词的通用定义总是正确的。很容易改进(正如我在回复中所显示的,几乎同时发布:-)使其尾部递归。@PauloMoura是的,很好的尾部递归解决方案。谢谢。谓词的两个版本之间还有另一个更微妙的区别。使用
(=:=)/2
进行比较意味着如果列表元素之一不是数字,则您的解决方案将引发异常,而我的解决方案将继续处理下一个元素。当然,问题陈述没有明确说明什么是更好的行为。很容易改进(正如我在回复中所显示的,几乎同时发布:-)使其尾部递归。@PauloMoura是的,很好的尾部递归解决方案。谢谢。谓词的两个版本之间还有另一个更微妙的区别。使用
(=:=)/2
进行比较意味着如果列表元素之一不是数字,则您的解决方案将引发异常,而我的解决方案将继续处理下一个元素。当然,问题陈述并没有明确指出什么是更可取的行为。请注意,当所有列表参数都实例化时,您的(简洁而漂亮的)解决方案仅与我和Sergey发布的解决方案等效。当然,这是一个合理的期望。@PauloMoura谢谢你的提示!我编辑我的文章是为了考虑你的观点。干杯。请注意,当所有列表参数都被实例化时,您的(漂亮而简洁的)解决方案仅与我和Sergey发布的解决方案等效。当然,这是一个合理的期望。@PauloMoura谢谢你的提示!我编辑我的文章是为了考虑你的观点。干杯