0

所以,我花了很多时间试图解决这个问题,但几乎没有任何进展。希望你能帮助我。目标是,获取这样的列表(我们称之为 baselist)[[[feesc,11],[podshare,11]],[[feesc,11]],[]]. And make it become this: [[feesc,22],[podshare,11]]:。

我有一个谓词负责在结果列表中添加或求和。这是代码:

place_key([Key,Value], [], [Key,Value]).
place_key([Key,Value], [[Key,V]|Rest], [[Key,V1]|Rest]) :- V1 is V+Value.
place_key([Key,Value], [[K,V]|Rest], [[K,V]|List2]) :- Key \= K, place_key([Key,Value], Rest, List2)."

如果我手动调用此方法来模拟递归,它会完全按照我的意愿工作。例子:

 place_key([feesc,11], [], R), place_key([feesc,11],R,J). 
So J is = [[feesc,22]]. 

预期结果是正确的。问题在于递归。

所以基本上我需要做的是:遍历baselist,当到达每个key/par列表时,调用place_key并将其保存在堆栈中,以便递归将其保留到最后。只是要指出,我不想追加,我只需要 place_key 的最新结果。

到目前为止我做了什么:

fe([HO|T],NL,R) :- write(HO), place_key(HO,NL,RESULT), fe(T,RESULT,R).
fe(S,R):- fe(S,[],R).
fe([],[]).
feg([HO,T],R) :- fe(HO,RESULT), feg(T,RESULT), R = RESULT.
feg([],[]).

当我运行时:

[trace] 57 ?- feg([[[feesc,11]],[[feesc,11]]],R).
   Call: (6) feg([[[feesc, 11]], [[feesc, 11]]], _G21384) ? creep
   Call: (7) fe([[feesc, 11]], _G21484) ? creep
   Call: (8) fe([[feesc, 11]], [], _G21485) ? creep
   Call: (9) place_key([feesc, 11], [], _G21485) ? creep
   Exit: (9) place_key([feesc, 11], [], [[feesc, 11]]) ? creep //Until here, I think this is correct.
   Call: (9) fe([], [[feesc, 11]], _G21494) ? creep 
   Fail: (9) fe([], [[feesc, 11]], _G21494) ? creep
   Redo: (9) place_key([feesc, 11], [], _G21485) ? creep
   Fail: (9) place_key([feesc, 11], [], _G21485) ? creep
   Fail: (8) fe([[feesc, 11]], [], _G21485) ? creep
   Fail: (7) fe([[feesc, 11]], _G21484) ? creep
   Fail: (6) feg([[[feesc, 11]], [[feesc, 11]]], _G21384) ? creep
false.

我究竟做错了什么?

4

2 回答 2

0

您的问题是您没有为fe/3. 如您所见,除了您的 place_key 谓词外,您还有以下内容:

fe([HO|T],NL,R) :- write(HO), place_key(HO,NL,RESULT), fe(T,RESULT,R).
fe(S,R):- fe(S,[],R).
fe([],[]).
feg([HO,T],R) :- fe(HO,RESULT), feg(T,RESULT), R = RESULT.
feg([],[]).

我将尝试使它更具可读性,因此您可以看到发生了什么:

% fe/3 cases
fe([Head|Tail],Current,Result) :- write(Head), place_key(Head,Current,TempResult), fe(Tail,TempResult,Result).
% fe/2 cases
fe(S,R):- fe(S,[],R).
fe([],[]).
%% this case above is never used, as the first case always matches
% recursive and base cases for feg
feg([HO,T],R) :- fe(HO,RESULT), feg(T,RESULT), R = RESULT.
feg([],[]).

您应该将其重写如下:

fe([],Result,Result). 

这是您的基本情况,如果列表为空,则中间结果等于最终结果。Prolog 总是先尝试第一个可能的匹配,所以总是把你的基本情况放在首位。

fe([Head|Tail],Current,Result) :- write(Head), place_key(Head,Current,TempResult), fe(Tail,TempResult,Result).

这是您的递归案例,就像您之前所做的那样,我们将把它放在我们的基本案例之下。

我们可以放弃第二种fe/2情况,因为第一种情况总是匹配的,我们fe/3无论如何都要重写,它可以处理所有情况。

fe(S,R):- fe(S,[],R).

以下是您现有的feg/2案例。这也是一个错误,因为在你的第一个fe/2-predicate 之后,RESULT-variable 有一个值,但它仍然需要能够与 call 统一feq(T,RESULT),这将产生一个不同的值。我将把它留作练习。

feg([HO,T],R) :- fe(HO,RESULT), feg(T,RESULT), R = RESULT.
feg([],[]).
于 2015-05-06T06:47:22.900 回答
0

将您的密钥/对保留为tuple,这是一个简单的术语,数量为 2。类似K-VorK:V甚至tuple(K,V)优于[K,V]. 这有一个简单的原因:

  • K-V,K:V并且tuple(K,V)都映射到简单的结构:-(K,V),:(K,V)tuple(K,V)分别, 而...

  • [K,V]是一个相当复杂的结构的语法糖.(K,.(V,[]))

此外,您可能会意识到您的键/值对很难与嵌套列表区分开来。将键/值对保持为元组使这种区别变得清晰。

因此,让我们假设您的键/值对表示为K:V。在我看来,您本质上想要做的是遍历嵌套列表(本质上是一棵树),枚举它包含的键/值对并生成集合(唯一)。这是一种方法。

首先,一个简单的谓词来识别一个非空列表:

nonnempty_list( L ) :- nonvar(L) , L = [_|_] .

然后,一个简单的谓词遍历列表的嵌套列表并枚举它找到的每个键/值对:

visit( [ K:R | Ls ] , K:R ) . % succeed if the head of the list is a key/value pair.
visit( [ L | Ls ] , KVP ) :-  % otherwise...
  nonempty_list(L) ,          % - if the head is a non-empty list ,
  visit( L , KVP )            % - visit it.
  .                           %
visit( [_|Ls] , KVP ) :-      % finally...
  visit( Ls , KVP )           % - recurse down on the tail.
  .                           %

然后你可以使用的魔法setof/3得到你想要的:

flattened_set( LoL , KVPs ) :-
  setof( KVP , visit(LoL,KVP) , KVPs )
  .
于 2015-05-07T17:42:45.220 回答