我正在尝试在Prolog中创建自己的排序规则,经过大量的反复试验后,我能够让它工作,除非我按下;在swipl中,它会将列表的最后一个值添加到列表中。
使用的代码如下:
min在列表中找到最小值并将其返回
min([H|[]],H).
min([H|T],Min) :-
min(T,CurrentMin),
H < CurrentMin,
Min = H.
min([H|T],Min) :-
min(T,CurrentMin),
CurrentMin =< H,
Min = CurrentMin.
remove在列表中查找要删除的元素,并返回一个删除了元素的列表
remove(_,[],[]).
remove(First,[First|Rest],Rest).
remove(Element,[First|Rest],[First|RestLessElement]) :-
remove(Element,Rest,RestLessElement).
最后,sort_inc尝试使用上述规则按递增顺序创建排序列表。
sort_inc([H|[]],[H]).
sort_inc(UnOrderedList,[H|OrderedTail]) :-
min(UnOrderedList,H),
remove(H,UnOrderedList,T),
sort_inc(T,OrderedTail).
排序效果很好,但是当我在列表上运行规则后按swipl中的分号时,它会重复列表中的最后一个值:
sort_inc([3,6,8,4],List).
List = [3, 4, 6, 8] ;
List = [3, 4, 6, 8, 8] ;
List = [3, 4, 6, 8, 8, 8] ;
List = [3, 4, 6, 8, 8, 8, 8] ;
List = [3, 4, 6, 8, 8, 8, 8, 8] ;
List = [3, 4, 6, 8, 8, 8, 8, 8, 8] ;
List = [3, 4, 6, 8, 8, 8, 8, 8, 8|...] .
为什么重复这最后一个值而不是在输入分号时返回false?
答案 0 :(得分:4)
你的remove / 3实现中有问题,请尝试这样做:
remove(X, [X|Rest], Result) :-
!, remove_sub(X, [X|Rest], Result).
remove(X, [Y|Rest], Z) :-
X \= Y,
remove(X, Rest, RestRemoved),
Z = [Y|RestRemoved].
remove(_, [], []).
remove_sub(X, [X|Rest], Rest).
remove_sub(X, [Y|Rest], Z) :-
remove_sub(X, Rest, RestRemoved),
Z = [Y|RestRemoved].
确切地说,删除/ 3的第一个子句会使列表保持不变,即使要删除的元素是其成员,也会生成不正确的解决方案:
?- remove(1, [1, 2, 3], L).
L = [2, 3] ;
L = [1, 2, 3].
另外,请记住,许多Prolog实现将捆绑删除/ 3和min / 2实现(当然还有排序)。例如,Swi-Prolog包括:
即使您的目标是创建自定义实现,仍然值得使用它们来测试您自己的实现,例如您可以使用delete / 3快速替换对remove / 3的调用,以找出问题所在。