如何摆脱反向使用?

问题描述 投票:1回答:2

我正在尝试解决chapter 6's excercises on LPN!中的以下问题:

编写一个谓词集(InList,OutList),该谓词集将任意列表作为输入,并返回一个列表,其中输入列表的每个元素仅出现一次。例如,查询

set([2,2,foo,1,foo, [],[]],X).

应该产生结果

X = [2,foo,1,[]].

我知道了:

set_([], [], []).

set_([H|Bag], [H|Set], Dups):-
  set_(Bag, Set, Dups),
  \+ member(H, Set),
  \+ member(H, Dups).

set_([H|Bag], Set, [H|Dups]):-
  set_(Bag, Set, Dups),
  member(H, Set).


set(Bag, Set, Rest):-
    reverse(BagR, Bag),
    set_(BagR, SetR, RestR),
    reverse(SetR, Set),
    reverse(RestR, Rest).

set(Bag, Set):- set(Bag, Set, _).

但是我对这3个reverse/2并没有什么印象。有人可以帮助我找到更优雅的解决方案吗?

我先尝试做一个右递归解决方案,但是试图证明问题可以“继续”会陷入困境。例如,如果我叫set_([1,2,1], L, R),则证明set(_, [1,2|_], [1|_]).会卡住。如果您有关于如何避免这种情况的反馈,请告诉我!

prolog swi-prolog
2个回答
0
投票
我最终使用了foldl/4

pushForward(X, [Set0, Rest], [Set, Rest]):- \+ member(X, Set0), append([Set0, [X]], Set). pushForward(X, [Set, Rest0], [Set, Rest]):- member(X, Set), append([Rest0, [X]], Rest). set(Bag, Set, Rest):- foldl(pushForward, Bag, [[],[]], [Set, Rest]). set(Bag, Set):- set(Bag, Set, _).


0
投票
在Prolog中,总是有必要寻求最简单的解决方案,所以

    使用简单的递归将元素从InList复制到累加器,如果尚未存在,则
  • 仅。将结果累加器反转为OutList。
  • 作为微优化,可以使用memberchk / 2而不是member / 2来检查是否应丢弃该元素。

由于您正在学习该语言,因此我不会显示完整的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.