Prolog 的内置反向函数作用为奇数

Prolog's built-in reverse function acting odd

给定以下代码:

fun(a, [b]).
fun(b, [c]).
fun(c, [d]).
fun(d, [e]).
fun(e, []).

xyz(X, Y):-
    fun(X,Z) -> findall([A|B], (member(A,Z), xyz(A,B)), L),
    flatten(L,F), sort(F,J), reverse(J,Y); Y = [].

通过查询 xyz(a,X) 我得到了预期的输出 X = [e,d,c,b].

可能是什么原因造成的?这与排序功能有关吗?如果是这样,根据下面链接中的文档,字母或数字的优先顺序可能会被取消,但它仍然不能解释 cs40cs30 之前。我很难找到相关性。我该如何解决这个问题?

http://www.swi-prolog.org/pldoc/doc_for?object=sort/2 http://www.swi-prolog.org/pldoc/man?section=compare

顺便说一句,fun 函数可以有多个元素列表,例如 fun(a, [b,c],其中 a 具有多个依赖项 bc . 这方面对于我当前的问题应该没有太大关系,只是把这个事实摆在那里。


更新

感谢@lurker,我取得了一些很大的进步。

给定以下代码:

final_xyz(X, Y):- xyz(X, R), reverse(R, Y).
xyz(X, Y) :-
    fun(X,Z) -> findall([A|B], (member(A,Z), xyz(A,B)), L),
    flatten(L,Y); Y = [].

为了解决这个问题,我将代码更新为:

xyz-final(X,Y):-
  fun(X,Z),
  Z\=0,
  ( length(Z,1) -> xyz(X,J), reverse(J,Y)
  ;
      xyz2(X,B), sort(B,C), reverse(C,Y)
  ).

xyz(K, [X|Y]):- fun(K, [X]), !, xyz(X, Y).
xyz(_, []).

xyz2(X, Y) :-
    fun(X,Z) -> findall([A|B], (member(A,Z), xyz2(A,B)), L),
    flatten(L,Y); Y = [].

非常笨拙的方法,但现在这似乎对我有用。我会努力提高效率。

问题是您想要反转最终结果,但您的反转是在对 xyz/2 的每次递归调用中完成的。如果您在 xyz(cs140a, X) 调用中执行 trace,您会看到它在不同的递归中被调用了几次。

如果你想要最后一次,那么你可以这样写:

final_xyz(X, Y) :-
    xyz(X, R),
    reverse(R, Y).
xyz(X, Y) :-
    fun(X,Z) -> findall([A|B], (member(A,Z), xyz(A,B)), L),
    flatten(L,Y); Y = [].

然后调用 final_xyz(cs140a, X) 产生 X = [m16a,cs30,cs40,cs110]


这是 xyz 谓词的另一种方法,它避免了 findallflatten。此版本应避免循环路径且不显示重复项:

xyz(X, Y) :-
    fun(X, L),
    xyz(L, [], R),
    reverse(R, Y).

xyz([H|T], A, R) :-
    (   memberchk(H, A)
    ->  xyz(T, A, R)
    ;   fun(H, L)
    ->  xyz(L, [H|A], R1),
        xyz(T, R1, R)
    ;   xyz(T, [H|A], R)
    ).
xyz([], A, A).