在 prolog 中解压一个列表
Decompression of a list in prolog
我需要在 prolog 中解压一个列表,如下例所示:
decode([[a,1],[b,2],[c,1],[d,3]],L).
L = [a, b, b, c, d, d, d] ;
我编写了这段代码:
divide(L,X,Y):-length(X,1),append(X,Y,L).
divide2(L,X,Y):-divide(L,[X|_],[Y|_]).
makelist(_,N,[]):- N =< 0 .
makelist(X,Y,[X|Result]):-Y1 is Y-1,makelist(X,Y1,Result).
makelist2(L,L2):-divide2(L,X,Y),makelist(X,Y,L2).
decode([],[]).
decode([H|T],L):-makelist2(H,H2),append(H2,L,L2),decode(T,L2).
当我打电话给
makelist2([a,3],L2).
L2 = [a,a,a].
但是当我打电话时
decode([[a,3],[b,1],[c,4]],L)
连续运行。我做错了什么?
问题出在decode
的最后一个子句中append
和decode
的顺序。尝试追踪它,或者更好的是,追踪它 "by hand" 看看会发生什么。
另一种方法:参见 this answer。因此,repeat/3
定义为:
% True when L is a list with N repeats of X
repeat(X, N, L) :-
length(L, N),
maplist(=(X), L).
您可以将 decode/2
写为:
decode([], []).
decode([[X,N]|XNs], Decoded) :-
decode(XNs, Decoded_rest),
repeat(X, N, L),
append(L, Decoded_rest, Decoded).
但这是一种稍微迂回的方式。您可以定义 repeat/3
的差异列表版本,称为 repeat/4
:
repeat(X, N, Reps, Reps_back) :-
( succ(N0, N)
-> Reps = [X|Reps0],
repeat(X, N0, Reps0, Reps_back)
; Reps = Reps_back
).
然后你可以使用decode/2
、decode_1/3
的差异列表版本
decode(Encoded, Decoded) :-
decode_1(Encoded, Decoded, []).
decode_1([], Decoded, Decoded).
decode_1([[X,N]|XNs], Decoded, Decoded_back) :-
repeat(X, N, Decoded, Decoded_rest),
decode_1(XNs, Decoded_rest, Decoded_back).
?- decode([[a,1],[b,2],[c,1],[d,3]],L).
L = [a, b, b, c, d, d, d].
?- decode([[a,3],[b,1],[c,0],[d,3]],L).
L = [a, a, a, b, d, d, d].
?- decode([[a,3]],L).
L = [a, a, a].
?- decode([],L).
L = [].
一种紧凑的方式:
decode(L,D) :- foldl(expand,L,[],D).
expand([S,N],L,E) :- findall(S,between(1,N,_),T), append(L,T,E).
findall/3 这是 'old fashioned' Prolog 列表理解工具
主题的另一个变体,使用鲍里斯 repeat/3
谓词的略微修改版本:
% True when L is a list with N repeats of X
repeat([X, N], L) :-
length(L, N),
maplist(=(X), L).
decode(Encoded, Decoded) :-
maplist(repeat, Encoded, Expanded),
flatten(Expanded, Decoded).
如果Encode = [[a,1],[b,2],[c,1],[d,3]]
,那么在上面的decode/2
中,maplist/3
调用会产生Expanded = [[a],[b,b],[c],[d,d,d]]
,然后flatten/2
调用会产生Decoded = [a,b,b,c,d,d,d]
.
在 SWI Prolog 中,您可以使用 append/2
而不是 flatten/2
,因为您只需要一个级别的 "flattening"。
编辑:添加一个 "bidirectional" 版本,使用一点 CLPFD:
rle([], []).
rle([X], [[1,X]]).
rle([X,Y|T], [[1,X]|R]) :-
X \== Y, % use dif(X, Y) here, if available
rle([Y|T], R).
rle([X,X|T], [[N,X]|R]) :-
N #= N1 + 1,
rle([X|T], [[N1,X]|R]).
这将产生:
| ?- rle([a,a,a,b,b], L).
L = [[3,a],[2,b]] ? ;
(1 ms) no
| ?- rle(L, [[3,a],[2,b]]).
L = [a,a,a,b,b] ? ;
no
| ?- rle([a,a,a,Y,Y,Z], [X, [N,b],[M,c]]).
M = 1
N = 2
X = [3,a]
Y = b
Z = c ? a
no
| ?- rle([A,B,C], D).
D = [[1,A],[1,B],[1,C]] ? ;
C = B
D = [[1,A],[2,B]] ? ;
B = A
D = [[2,A],[1,C]] ? ;
B = A
C = A
D = [[3,A]] ? ;
(2 ms) no
| ?- rle(A, [B,C]).
A = [D,E]
B = [1,D]
C = [1,E] ? ;
A = [D,E,E]
B = [1,D]
C = [2,E] ? ;
A = [D,E,E,E]
B = [1,D]
C = [3,E] ? ;
...
| ?- rle(A, B).
A = []
B = [] ? ;
A = [C]
B = [[1,C]] ? ;
A = [C,D]
B = [[1,C],[1,D]] ? ;
...
正如@mat 在他的评论中建议的那样,在具有 dif/2
的 Prolog 实现中,dif(X,Y)
优于上面的 X \== Y
。
您可以使用此代码处理两个方向:
:- use_module(library(lambda)).
% code from Pascal Bourguignon
packRuns([],[]).
packRuns([X],[[X]]).
packRuns([X|Rest],[XRun|Packed]):-
run(X,Rest,XRun,RRest),
packRuns(RRest,Packed).
run(Var,[],[Var],[]).
run(Var,[Var|LRest],[Var|VRest],RRest):-
run(Var,LRest,VRest,RRest).
run(Var,[Other|RRest],[Var],[Other|RRest]):-
dif(Var,Other).
%end code
pack_1(In, Out) :-
maplist(\X^Y^(X = [V|_],
Y = [V, N],
length(X, N),
maplist(=(V), X)),
In, Out).
decode(In, Out) :-
when((ground(In); ground(Out1)),pack_1(Out1, In)),
packRuns(Out, Out1).
输出:
?- decode([[a,1],[b,2],[c,1],[d,3]],L).
L = [a, b, b, c, d, d, d] .
?- decode(L, [a,b,b,c,d,d,d]).
L = [[a, 1], [b, 2], [c, 1], [d, 3]] .
decode
是你的谓词的一个糟糕的名字:正确地完成,你的谓词应该是双向的——如果你说
decode( [[a,1],[b,2],[c,3]] , L )
你应该得到
L = [a,b,b,c,c,c].
如果你说
decode( L , [a,b,b,c,c,c] ) .
你应该得到
L = [[a,1],[b,2],[c,3]].
所以我会使用不同的名称,例如 run_length_encoding/2
。我也可能不会使用列表来表示单个 运行 长度,因为 [a,1]
是这个序言术语:.(a,.(1,[])
。只需使用一个带有 arity 2 的简单术语——我自己,我喜欢使用 :/2
因为它被定义为一个中缀运算符,所以你可以简单地说 a:1
.
试穿尺码:
run_length_encoding( [] , [] ) . % the run-length encoding of the empty list is the empty list.
run_length_encoding( [X|Xs] , [R|Rs] ) :- % the run-length encoding of a non-empty list is computed by
rle( Xs , X:1 , T , R ) , % - run-length encoding the prefix of the list
run_length_encoding( T , Rs ) % - and recursively run-length encoding the remainder
. % Easy!
rle( [] , C:N , [] , C:N ) . % - the run is complete when the list is exhausted.
rle( [X|Xs] , C:N , [X|Xs] , C:N ) :- % - the run is complete,
X \= C % - when we encounter a break
. %
rle( [X|Xs] , X:N , T , R ) :- % - the run continues if we haven't seen a break, so....
N1 is N+1 , % - increment the run length,
rle( Xs, X:N1, T, R ) % - and recurse down.
. % Easy!
直接回答原始问题,我做错了什么?...
当我运行原始代码时,任何预期的用例"ran indefinitely"都没有产生结果。
阅读主谓词:
decode([],[]).
这表示[]
是解码[]
的结果。听起来不错。
decode([H|T],L) :- makelist2(H,H2), append(H2,L,L2), decode(T,L2).
这表示 L
是解码 [H|T]
的结果,如果 H2
是 H
的扩展(这就是 makelist2
所做的...... . 也许 - 我们将在下面讨论),并且附加到此结果的 H2
给出另一个列表 L2
,这是原始尾部 T
的解码形式。这听起来不正确。如果我解码 [H|T]
,我应该 (1) 扩展 H
,(2) 解码 T
给出 L2
,然后 (3) 将 H
附加到 L2
给出 L
.
所以更正后的第二个子句是:
decode([H|T], L) :- makelist2(H, H2), decode(T, L2), append(H2, L2, L).
注意 append/3
的参数顺序,调用发生在尾部的 decode
之后。正如 Boris 先前指出的那样,append
和递归 decode
的错误顺序会导致连续的 运行 没有任何输出,因为 append
具有更多未实例化的参数会生成大量decode
成功之前不需要的可能性。
但现在的结果是:
| ?- decode([[a,3]], L).
L = [a,a,a] ? ;
L = [a,a,a,a] ? ;
...
如果您在 Prolog 解释器中手动尝试我们的其他谓词,您会发现 makelist2/2
有一个问题:
它产生了正确的结果,但也产生了一堆不正确的结果。我们来看看makelist2/2
。我们可以自己试试这个谓词,看看会发生什么:
| ?- makelist2([a,3], L).
L = [a,a,a] ? ;
L = [a,a,a,a] ? ;
...
存在一个问题:makelist2/2
应该只给出第一个解决方案,但它一直在继续,给出了错误的解决方案。让我们仔细看看 makelist/2
:
makelist2(L,L2) :- divide2(L,X,Y), makelist(X,Y,L2).
它采用 [A,N]
形式的列表 L
,将其(通过 divide2/3
)分为 X = A
和 Y = N
,然后调用辅助, makelist(X, Y, L2)
.
makelist(_,N,[]):- N =< 0 .
makelist(X,Y,[X|Result]):-Y1 is Y-1,makelist(X,Y1,Result).
makelist/3
应该通过将第一个参数复制第二个参数中给定的次数来生成列表(第三个参数)。第二个递归子句看起来没问题,但有一个重要缺陷:即使 Y
的值小于或等于 0
,它也会成功。因此,即使找到了正确的解决方案,它也会在不正确的解决方案上继续取得成功,因为基本情况允许计数为 =< 0
:
| ?- makelist(a,2,L).
L = [a,a] ? ;
L = [a,a,a] ? ;
我们可以修复makelist/2
如下:
makelist(_,N,[]):- N =< 0 .
makelist(X,Y,[X|Result]):- Y > 0, Y1 is Y-1, makelist(X,Y1,Result).
现在代码将生成正确的结果。我们只需要修复 decode/2
的第二个子句和 makelist/3
.
的第二个子句
| ?- decode([[a,3],[b,4]], L).
L = [a,a,a,b,b,b,b]
yes
完整的原始代码,仅进行了这几处更正,如下所示:
divide(L, X, Y) :- length(X, 1), append(X, Y, L).
divide2(L, X, Y) :- divide(L, [X|_], [Y|_]).
makelist(_, N, []) :- N =< 0 .
makelist(X, Y, [X|Result]) :- Y > 0, Y1 is Y-1, makelist(X,Y1,Result).
makelist2(L, L2) :- divide2(L, X, Y), makelist(X, Y, L2).
decode([], []).
decode([H|T], L) :- makelist2(H,H2), decode(T,L2), append(H2,L2,L).
注意一些简单、直接的改进。谓词 divide2(L, X, Y)
获取包含两个元素的列表 L
并生成每个单独的元素 X
和 Y
。这个谓词是不必要的,因为在 Prolog 中,您可以通过简单的统一获得这些元素:L = [X, Y]
。您可以在 Prolog 解释器中尝试这样做:
| ?- L = [a,3], L = [X,Y].
L = [a,3]
X = a
Y = 3
yes
然后我们可以完全删除 divide/3
和 divide2/3
谓词,并将对 divide2(L, X, Y)
的调用替换为 L = [X,Y]
并将 makelist2/2
减少为:
makelist2(L, L2) :- L = [X, Y], makelist(X, Y, L2).
或者更简单(因为我们可以在子句的头部进行统一):
makelist2([X,Y], L2) :- makelist(X, Y, L2).
您可以删除 makelist2/2
并直接从 decode/2
调用 makelist/2
,方法是将 H
直接与其两个元素 [X, N]
统一起来。所以原代码简化为:
makelist(_, N, []) :- N =< 0 .
makelist(X, Y, [X|Result]) :- Y > 0, Y1 is Y-1, makelist(X,Y1,Result).
decode([], []).
decode([[X,N]|T], L) :- makelist(X, N, H2), decode(T, L2), append(H2, L2, L).
并且 makelist/3
可以使用其他答案中提供的方法之一更清楚地执行(例如,请参阅鲍里斯的 repeat/3
谓词).
我需要在 prolog 中解压一个列表,如下例所示:
decode([[a,1],[b,2],[c,1],[d,3]],L).
L = [a, b, b, c, d, d, d] ;
我编写了这段代码:
divide(L,X,Y):-length(X,1),append(X,Y,L).
divide2(L,X,Y):-divide(L,[X|_],[Y|_]).
makelist(_,N,[]):- N =< 0 .
makelist(X,Y,[X|Result]):-Y1 is Y-1,makelist(X,Y1,Result).
makelist2(L,L2):-divide2(L,X,Y),makelist(X,Y,L2).
decode([],[]).
decode([H|T],L):-makelist2(H,H2),append(H2,L,L2),decode(T,L2).
当我打电话给
makelist2([a,3],L2).
L2 = [a,a,a].
但是当我打电话时
decode([[a,3],[b,1],[c,4]],L)
连续运行。我做错了什么?
问题出在decode
的最后一个子句中append
和decode
的顺序。尝试追踪它,或者更好的是,追踪它 "by hand" 看看会发生什么。
另一种方法:参见 this answer。因此,repeat/3
定义为:
% True when L is a list with N repeats of X
repeat(X, N, L) :-
length(L, N),
maplist(=(X), L).
您可以将 decode/2
写为:
decode([], []).
decode([[X,N]|XNs], Decoded) :-
decode(XNs, Decoded_rest),
repeat(X, N, L),
append(L, Decoded_rest, Decoded).
但这是一种稍微迂回的方式。您可以定义 repeat/3
的差异列表版本,称为 repeat/4
:
repeat(X, N, Reps, Reps_back) :-
( succ(N0, N)
-> Reps = [X|Reps0],
repeat(X, N0, Reps0, Reps_back)
; Reps = Reps_back
).
然后你可以使用decode/2
、decode_1/3
decode(Encoded, Decoded) :-
decode_1(Encoded, Decoded, []).
decode_1([], Decoded, Decoded).
decode_1([[X,N]|XNs], Decoded, Decoded_back) :-
repeat(X, N, Decoded, Decoded_rest),
decode_1(XNs, Decoded_rest, Decoded_back).
?- decode([[a,1],[b,2],[c,1],[d,3]],L).
L = [a, b, b, c, d, d, d].
?- decode([[a,3],[b,1],[c,0],[d,3]],L).
L = [a, a, a, b, d, d, d].
?- decode([[a,3]],L).
L = [a, a, a].
?- decode([],L).
L = [].
一种紧凑的方式:
decode(L,D) :- foldl(expand,L,[],D).
expand([S,N],L,E) :- findall(S,between(1,N,_),T), append(L,T,E).
findall/3 这是 'old fashioned' Prolog 列表理解工具
主题的另一个变体,使用鲍里斯 repeat/3
谓词的略微修改版本:
% True when L is a list with N repeats of X
repeat([X, N], L) :-
length(L, N),
maplist(=(X), L).
decode(Encoded, Decoded) :-
maplist(repeat, Encoded, Expanded),
flatten(Expanded, Decoded).
如果Encode = [[a,1],[b,2],[c,1],[d,3]]
,那么在上面的decode/2
中,maplist/3
调用会产生Expanded = [[a],[b,b],[c],[d,d,d]]
,然后flatten/2
调用会产生Decoded = [a,b,b,c,d,d,d]
.
在 SWI Prolog 中,您可以使用 append/2
而不是 flatten/2
,因为您只需要一个级别的 "flattening"。
编辑:添加一个 "bidirectional" 版本,使用一点 CLPFD:
rle([], []).
rle([X], [[1,X]]).
rle([X,Y|T], [[1,X]|R]) :-
X \== Y, % use dif(X, Y) here, if available
rle([Y|T], R).
rle([X,X|T], [[N,X]|R]) :-
N #= N1 + 1,
rle([X|T], [[N1,X]|R]).
这将产生:
| ?- rle([a,a,a,b,b], L).
L = [[3,a],[2,b]] ? ;
(1 ms) no
| ?- rle(L, [[3,a],[2,b]]).
L = [a,a,a,b,b] ? ;
no
| ?- rle([a,a,a,Y,Y,Z], [X, [N,b],[M,c]]).
M = 1
N = 2
X = [3,a]
Y = b
Z = c ? a
no
| ?- rle([A,B,C], D).
D = [[1,A],[1,B],[1,C]] ? ;
C = B
D = [[1,A],[2,B]] ? ;
B = A
D = [[2,A],[1,C]] ? ;
B = A
C = A
D = [[3,A]] ? ;
(2 ms) no
| ?- rle(A, [B,C]).
A = [D,E]
B = [1,D]
C = [1,E] ? ;
A = [D,E,E]
B = [1,D]
C = [2,E] ? ;
A = [D,E,E,E]
B = [1,D]
C = [3,E] ? ;
...
| ?- rle(A, B).
A = []
B = [] ? ;
A = [C]
B = [[1,C]] ? ;
A = [C,D]
B = [[1,C],[1,D]] ? ;
...
正如@mat 在他的评论中建议的那样,在具有 dif/2
的 Prolog 实现中,dif(X,Y)
优于上面的 X \== Y
。
您可以使用此代码处理两个方向:
:- use_module(library(lambda)).
% code from Pascal Bourguignon
packRuns([],[]).
packRuns([X],[[X]]).
packRuns([X|Rest],[XRun|Packed]):-
run(X,Rest,XRun,RRest),
packRuns(RRest,Packed).
run(Var,[],[Var],[]).
run(Var,[Var|LRest],[Var|VRest],RRest):-
run(Var,LRest,VRest,RRest).
run(Var,[Other|RRest],[Var],[Other|RRest]):-
dif(Var,Other).
%end code
pack_1(In, Out) :-
maplist(\X^Y^(X = [V|_],
Y = [V, N],
length(X, N),
maplist(=(V), X)),
In, Out).
decode(In, Out) :-
when((ground(In); ground(Out1)),pack_1(Out1, In)),
packRuns(Out, Out1).
输出:
?- decode([[a,1],[b,2],[c,1],[d,3]],L).
L = [a, b, b, c, d, d, d] .
?- decode(L, [a,b,b,c,d,d,d]).
L = [[a, 1], [b, 2], [c, 1], [d, 3]] .
decode
是你的谓词的一个糟糕的名字:正确地完成,你的谓词应该是双向的——如果你说
decode( [[a,1],[b,2],[c,3]] , L )
你应该得到
L = [a,b,b,c,c,c].
如果你说
decode( L , [a,b,b,c,c,c] ) .
你应该得到
L = [[a,1],[b,2],[c,3]].
所以我会使用不同的名称,例如 run_length_encoding/2
。我也可能不会使用列表来表示单个 运行 长度,因为 [a,1]
是这个序言术语:.(a,.(1,[])
。只需使用一个带有 arity 2 的简单术语——我自己,我喜欢使用 :/2
因为它被定义为一个中缀运算符,所以你可以简单地说 a:1
.
试穿尺码:
run_length_encoding( [] , [] ) . % the run-length encoding of the empty list is the empty list.
run_length_encoding( [X|Xs] , [R|Rs] ) :- % the run-length encoding of a non-empty list is computed by
rle( Xs , X:1 , T , R ) , % - run-length encoding the prefix of the list
run_length_encoding( T , Rs ) % - and recursively run-length encoding the remainder
. % Easy!
rle( [] , C:N , [] , C:N ) . % - the run is complete when the list is exhausted.
rle( [X|Xs] , C:N , [X|Xs] , C:N ) :- % - the run is complete,
X \= C % - when we encounter a break
. %
rle( [X|Xs] , X:N , T , R ) :- % - the run continues if we haven't seen a break, so....
N1 is N+1 , % - increment the run length,
rle( Xs, X:N1, T, R ) % - and recurse down.
. % Easy!
直接回答原始问题,我做错了什么?...
当我运行原始代码时,任何预期的用例"ran indefinitely"都没有产生结果。
阅读主谓词:
decode([],[]).
这表示[]
是解码[]
的结果。听起来不错。
decode([H|T],L) :- makelist2(H,H2), append(H2,L,L2), decode(T,L2).
这表示 L
是解码 [H|T]
的结果,如果 H2
是 H
的扩展(这就是 makelist2
所做的...... . 也许 - 我们将在下面讨论),并且附加到此结果的 H2
给出另一个列表 L2
,这是原始尾部 T
的解码形式。这听起来不正确。如果我解码 [H|T]
,我应该 (1) 扩展 H
,(2) 解码 T
给出 L2
,然后 (3) 将 H
附加到 L2
给出 L
.
所以更正后的第二个子句是:
decode([H|T], L) :- makelist2(H, H2), decode(T, L2), append(H2, L2, L).
注意 append/3
的参数顺序,调用发生在尾部的 decode
之后。正如 Boris 先前指出的那样,append
和递归 decode
的错误顺序会导致连续的 运行 没有任何输出,因为 append
具有更多未实例化的参数会生成大量decode
成功之前不需要的可能性。
但现在的结果是:
| ?- decode([[a,3]], L).
L = [a,a,a] ? ;
L = [a,a,a,a] ? ;
...
如果您在 Prolog 解释器中手动尝试我们的其他谓词,您会发现 makelist2/2
有一个问题:
它产生了正确的结果,但也产生了一堆不正确的结果。我们来看看makelist2/2
。我们可以自己试试这个谓词,看看会发生什么:
| ?- makelist2([a,3], L).
L = [a,a,a] ? ;
L = [a,a,a,a] ? ;
...
存在一个问题:makelist2/2
应该只给出第一个解决方案,但它一直在继续,给出了错误的解决方案。让我们仔细看看 makelist/2
:
makelist2(L,L2) :- divide2(L,X,Y), makelist(X,Y,L2).
它采用 [A,N]
形式的列表 L
,将其(通过 divide2/3
)分为 X = A
和 Y = N
,然后调用辅助, makelist(X, Y, L2)
.
makelist(_,N,[]):- N =< 0 .
makelist(X,Y,[X|Result]):-Y1 is Y-1,makelist(X,Y1,Result).
makelist/3
应该通过将第一个参数复制第二个参数中给定的次数来生成列表(第三个参数)。第二个递归子句看起来没问题,但有一个重要缺陷:即使 Y
的值小于或等于 0
,它也会成功。因此,即使找到了正确的解决方案,它也会在不正确的解决方案上继续取得成功,因为基本情况允许计数为 =< 0
:
| ?- makelist(a,2,L).
L = [a,a] ? ;
L = [a,a,a] ? ;
我们可以修复makelist/2
如下:
makelist(_,N,[]):- N =< 0 .
makelist(X,Y,[X|Result]):- Y > 0, Y1 is Y-1, makelist(X,Y1,Result).
现在代码将生成正确的结果。我们只需要修复 decode/2
的第二个子句和 makelist/3
.
| ?- decode([[a,3],[b,4]], L).
L = [a,a,a,b,b,b,b]
yes
完整的原始代码,仅进行了这几处更正,如下所示:
divide(L, X, Y) :- length(X, 1), append(X, Y, L).
divide2(L, X, Y) :- divide(L, [X|_], [Y|_]).
makelist(_, N, []) :- N =< 0 .
makelist(X, Y, [X|Result]) :- Y > 0, Y1 is Y-1, makelist(X,Y1,Result).
makelist2(L, L2) :- divide2(L, X, Y), makelist(X, Y, L2).
decode([], []).
decode([H|T], L) :- makelist2(H,H2), decode(T,L2), append(H2,L2,L).
注意一些简单、直接的改进。谓词 divide2(L, X, Y)
获取包含两个元素的列表 L
并生成每个单独的元素 X
和 Y
。这个谓词是不必要的,因为在 Prolog 中,您可以通过简单的统一获得这些元素:L = [X, Y]
。您可以在 Prolog 解释器中尝试这样做:
| ?- L = [a,3], L = [X,Y].
L = [a,3]
X = a
Y = 3
yes
然后我们可以完全删除 divide/3
和 divide2/3
谓词,并将对 divide2(L, X, Y)
的调用替换为 L = [X,Y]
并将 makelist2/2
减少为:
makelist2(L, L2) :- L = [X, Y], makelist(X, Y, L2).
或者更简单(因为我们可以在子句的头部进行统一):
makelist2([X,Y], L2) :- makelist(X, Y, L2).
您可以删除 makelist2/2
并直接从 decode/2
调用 makelist/2
,方法是将 H
直接与其两个元素 [X, N]
统一起来。所以原代码简化为:
makelist(_, N, []) :- N =< 0 .
makelist(X, Y, [X|Result]) :- Y > 0, Y1 is Y-1, makelist(X,Y1,Result).
decode([], []).
decode([[X,N]|T], L) :- makelist(X, N, H2), decode(T, L2), append(H2, L2, L).
并且 makelist/3
可以使用其他答案中提供的方法之一更清楚地执行(例如,请参阅鲍里斯的 repeat/3
谓词).