错误:处理Prolog列表对时“超出全局堆栈”

时间:2012-08-07 09:26:22

标签: prolog

在SWI-Prolog中,我有一个列表,其元素是Key-ValuesList形式的对。例如,一个这样的列表可能看起来像:

[1-[a,b],2-[],3-[c]]

我想将此列表转换为Key- [Value]形式的对的嵌套列表,其中Value是ValuesList中的元素。以上示例将转换为:

[[1-[a],2-[],3-[c]], [1-[b],2-[],3-[c]]]

我目前的解决方案如下:

% all_pairs_lists(+InputList, -OutputLists).
all_pairs_lists([], [[]]).
all_pairs_lists([Key-[]|Values], CP) :-
  !,
  findall([Key-[]|R], (all_pairs_lists(Values,RCP), member(R,RCP)), CP).
all_pairs_lists([Key-Value|Values], CP) :-
  findall([Key-[V]|R], (all_pairs_lists(Values,RCP), member(V,Value), member(R,RCP)), CP).

使用此谓词,调用表单

all_pairs_lists([1-[a,b],2-[],3-[c]],OutputLists).

将变量OutputLists绑定到上面提到的所需结果。虽然看起来是正确的,但是当InputList将列表作为值很长时,此实现会导致“Out of global stack”错误。

这样做是否有更少的堆栈消耗方法?对于这种类型的数据结构来说,这似乎是一种常见的操作。

2 个答案:

答案 0 :(得分:2)

嗯,总而言之,你做错了。

在Prolog中,当我们想要表达关系而不是函数时(可能有几个结果而不是一个),我们不能直接使用findall/3member/2。我们宁愿陈述关系是什么,然后如果我们需要一个我们使用findall/3的结果列表就可以完成。

这意味着我们想要表达以下关系:

  

获取Key-Values列表并返回Key-[Value]列表,其中ValueValues列表的成员。

我们可以这样做:

% The base case: handle the empty list
a_pair_list([], []).

% The case where the Values list is empty, then the resulting [Value] is []
a_pair_list([Key-[]|List], [Key-[]|Result]) :-
    a_pair_list(List, Result).
% The case where the Values list is not empty, then Value is a member of Values.
a_pair_list([Key-[Not|Empty]|List], [Key-[Value]|Result]) :-
    member(Value, [Not|Empty]),
    a_pair_list(List, Result).

一旦表达了这种关系,我们就可以获得我们想要的所有信息:

?- a_pair_list([1-[a, b], 2-[], 3-[c]], Result).
Result = [1-[a], 2-[], 3-[c]] ;
Result = [1-[b], 2-[], 3-[c]] ;
false.

所需的列表现在只是一个相当简单的findall/3来电:

all_pairs_lists(Input, Output) :-
    findall(Result, a_pair_list(Input, Result), Output).

要记住的重要一点是,远离额外的逻辑内容会更好:!/0findall/3等...因为它经常导致较少的一般程序和/或不太正确的程序。在这里,因为我们可以以纯粹和干净的方式表达上述关系,我们应该。通过这种方式,我们可以将findall/3的烦恼限制在最低限度。

答案 1 :(得分:2)

由于@Mog已经清楚地解释了问题所在,这里有一个版本(ab)使用基本的'functional'内置列表处理:

all_pairs_lists(I, O) :-
    findall(U, maplist(pairs_lists, I, U), O).

pairs_lists(K-[], K-[]) :- !.
pairs_lists(K-L, K-[R]) :- member(R, L).

试验:

?- all_pairs_lists([1-[a,b],2-[],3-[c]],OutputLists).
OutputLists = [[1-[a], 2-[], 3-[c]], [1-[b], 2-[], 3-[c]]].
相关问题