2

我在 Prolog(SWI-Prolog)中有一个非常简单的(我想)问题,但我无法弄清楚。

我想要的是创建一个能够将任何嵌套列表交换为复合术语的递归谓词。

我想在这两种表示之间进行交换,因为我正在使用一种适用于列表表示的替代算法,并且我希望复合表示作为输出。

所以我想:

list_2_compound(List,Compound).

例如,它的工作原理是

list_2_compound([seq, [seq, [if, p1, p2], p2], p1, p3], Compound).

Compound = seq(seq(if(p1, p2), p2), p1, p3)

所以我通常想使用 =.. 运算符:

Compound =.. [if, p1, p2] 
Compound = if(p1,p2)

但现在以递归的方式横向到嵌套列表。

4

2 回答 2

4

乍一看比我想象的要棘手一些。

list_2_compound(L, T) :-
    var(T)
    ->  L = [F|Fs], maplist(list_2_compound, Fs, Ts), T =.. [F|Ts]
    ;   atomic(T)
    ->  L = T
    ;   L = [F|Fs], T =.. [F|Ts], maplist(list_2_compound, Fs, Ts).
list_2_compound(T, T).

(我之前的帖子在相反的情况下产生了太多的嵌套列表)。测试:

1 ?- list_2_compound([seq, [seq, [if, p1, p2], p2], p1, p3], Compound).
Compound = seq(seq(if(p1, p2), p2), p1, p3) 
.

2 ?- list_2_compound(S, $Compound).
S = [seq, [seq, [if, p1, p2], p2], p1, p3] 
.

编辑

在@damianodamiano 发表评论后,很明显有一个错误,但事实并非如此

无限次相同的解决方案

因为我们有

?- aggregate(count,L^list_2_compound(L, seq(seq(if(p1, p2), p2), p1, p3)),N).
N = 45.

最后,只是“catch all”子句与上面已经处理的案例重叠——毫无用处。但是为了避免混淆,并更好地利用这段代码的声明性属性,我将把谓词重命名为list_compound

list_compound(L, T) :-
    (   var(T)
    ->  L = [F|Fs], maplist(list_compound, Fs, Ts), T =.. [F|Ts]
    ;   atomic(T)
    ->  L = T
    ;   L = [F|Fs], T =.. [F|Ts], maplist(list_compound, Fs, Ts)
    ),
    !.
list_compound(T, T).

现在我们有了一个确定性的计算:

?- list_compound(L, seq(seq(if(p1, p2), p2), p1, p3)).
L = [seq, [seq, [if, p1, p2], p2], p1, p3].

?- list_compound($L, C).
C = seq(seq(if(p1, p2), p2), p1, p3),
L = [seq, [seq, [if, p1, p2], p2], p1, p3].

所以,这与@patta1986 在 2013 年的评论中解释的解决方案相同......

于 2013-11-12T00:06:13.013 回答
1

如果你想完全懒惰和纯粹,你可以使用when/2(coroutine) 来延迟计算,直到你有一个 nonvar 头函子。这样谓词(=...下面命名)在所有模式下都有效。

:- op(700, xfx, =...).
Term =... [Functor|Sublists] :-
    when((nonvar(Term) ; nonvar(Functor)),
         (var(Term)
         -> maplist(=..., Subterms, Sublists),
            Term =.. [Functor|Subterms]
         ;  Term =.. [Functor|Subterms],
            maplist(=..., Subterms, Sublists))).
?- f(X, g(Y)) =... L, X=1, Y=2.  % Mostly forwards
X = 1,
Y = 2,
L = [f, [1], [g, [2]]].

?- T =...  [f, [X], [g, [Y]]], X=1, Y=2.  % Mostly backwards
T = f(1, g(2)),
X = 1,
Y = 2.

?- Term =... List.  % Most general query
List = [_954|_956],
when((nonvar(Term);nonvar(_954)),  (var(Term)->maplist(=..., _1016, _956), Term=..[_954|_1016];Term=..[_954|_1016], maplist(=..., _1016, _956))).

该解决方案适用于完全嵌套的列表,我认为它更易于交互。

于 2022-02-21T01:36:48.950 回答