So I'm totally new to Prolog and need some help. I'm trying to take a list of lists like [[1,2,3],[4,5,6],[7,8]]
and create a list like [2,3,5,6,8]
, so basically all the values into a new list besides the first of each list. I got this:
所以我对Prolog很新,需要一些帮助。我正在尝试列出像[[1,2,3],[4,5,6],[7,8]]这样的列表,并创建一个像[2,3,5,6,8]这样的列表,所以除了每个列表的第一个之外,所有的值基本上都是新的列表。我懂了:
test5(X,[[_|X]|_]).
test5(X,[_|A]) :- test5(X,A).
which returns [2,3]
and then [5,6]
and then [8]
each time I press enter. I'm not sure how to make them run all at once and make them into a list. I tried using append in different ways but I could not get this working. Any idea on how to implement this? Thanks!
每次按回车键,返回[2,3]然后[5,6]再然后[8]。我不确定如何让它们一次运行并将它们放入列表中。我尝试以不同的方式使用追加,但我无法使其工作。有关如何实现这一点的任何想法?谢谢!
2 个解决方案
#1
You have the common predicate flatten/2
, which almost does the job:
你有共同的谓词flatten / 2,几乎完成了这项工作:
?- flatten([[1,2,3],[4,5,6],[7,8]], L).
L = [1, 2, 3, 4, 5, 6, 7, 8].
There are many implementations of flatten/2
available, just google it.
有很多flatten / 2可用的实现,只是google它。
If you know that the list of lists is not nested, you should rather use append/2
.
如果您知道列表列表未嵌套,则应使用append / 2。
Then, you need to drop the first element of each list before appending:
然后,您需要在追加之前删除每个列表的第一个元素:
list_tail([_|T], T).
Then:
?- maplist(list_tail, [[1,2,3],[4,5,6],[7,8]], T), append(T, L).
T = [[2, 3], [5, 6], [8]],
L = [2, 3, 5, 6, 8].
It might be a good exercise to take a more careful look at the implementation of append/2
linked above. With a small change in the definition (literally removing 1 character and adding 5) it will do the dropping and appending in the same step, without traversing the original list twice.
仔细研究上面链接的append / 2的实现可能是一个很好的练习。通过定义中的小变化(逐字地删除1个字符并添加5),它将执行删除并在同一步骤中追加,而不会遍历原始列表两次。
EDIT
So why is it that @repeat's initial solution does not terminate when the first argument is not a proper list, but the second is a proper list?
那么,为什么@ repeat的初始解决方案不会在第一个参数不是正确的列表时终止,但第二个是正确的列表?
nt_tails_append([[_|T]|Ls], As) :-
append(T, Ws, As),
nt_tails_append(Ls, Ws).
It is because when the first argument to nt_tails_append/2
is a free variable, the first two arguments to append/3
above are variables, too. When we call append/3
in this mode, we get, by definition:
这是因为当nt_tails_append / 2的第一个参数是一个*变量时,上面追加/ 3的前两个参数也是变量。当我们在这种模式下调用append / 3时,根据定义我们得到:
?- append(A, B, L).
A = [],
B = L .
In other words, the second and the third arguments are now unified. With the definition of nt_tail_append/2
, this means that the recursive call gets the same second argument as the original call, and a new free variable as the first argument. This is an endless loop, of course.
换句话说,第二个和第三个参数现在是统一的。通过定义nt_tail_append / 2,这意味着递归调用获得与原始调用相同的第二个参数,并将新的*变量作为第一个参数。当然,这是一个无限循环。
(Tellingly, if you care to look at the definition of append/2
linked above, you will see that the first argument must_be
a list
.)
(引人注目的是,如果你想看看上面链接的append / 2的定义,你会看到第一个参数must_be是一个列表。)
How does this help?
这有什么用?
tails_append(Ls, As) :-
maplist(list_tail, Ls, T),
append(T, As).
list_tail([_|T], T).
The way that maplist
is defined, all list arguments will be instantiated to proper lists. So you can safely use append/3
(here, used in the definition of append/2
).
定义maplist的方式,所有列表参数都将实例化为正确的列表。所以你可以安全地使用append / 3(这里,在append / 2的定义中使用)。
#2
Here is how you could do it using append/3
:
以下是使用append / 3的方法:
lists_concatenatedTails([],[]). lists_concatenatedTails([[_|Xs0]|Xss],Ys) :- append(Xs0,Ys0,Ys), lists_concatenatedTails(Xss,Ys0).
Sample query:
?- lists_concatenatedTails([[1,2,3],[4,5,6],[7,8]], Xs). Xs = [2, 3, 5, 6, 8].
Edit 2015-05-07
Note that the code that @Boris suggested (using list_tail/2
,maplist/3
,append/2
) also gives answers for the following query:
请注意,@ Boris建议的代码(使用list_tail / 2,maplist / 3,append / 2)也为以下查询提供了答案:
?- maplist(list_tail,Xss,Yss), append(Yss,[1,2,3]).
Xss = [[_G97, 1, 2, 3]], Yss = [[1, 2, 3]] ;
Xss = [[_G97], [_G106, 1, 2, 3]], Yss = [[], [1, 2, 3]] ;
Xss = [[_G97, 1], [_G106, 2, 3]], Yss = [[1], [2, 3]] ;
Xss = [[_G97, 1, 2], [_G106, 3]], Yss = [[1, 2], [3]] ;
Xss = [[_G97, 1, 2, 3], [_G106]], Yss = [[1, 2, 3], []] ;
Xss = [[_G97], [_G106], [_G115, 1, 2, 3]], Yss = [[], [], [1, 2, 3]] ...
This doesn't terminate universally---nor do we expect it to: the set of solutions is infinite in size and it can, in this case, only be covered by an infinite sequence of answers.
这并不是普遍终止的 - 我们也不期望它:解决方案集的大小是无限的,在这种情况下,它只能被无限的答案序列所覆盖。
In the following equivalent query lists_concatenatedTails/2
"loops" right away:
在以下等效查询中,lists_concatenatedTails / 2“循环”立即:
?- lists_concatenatedTails(Lss,[1,2,3]).
% not a single answer within finite time
Only when constraining the length of Lss
right away, fair enumeration can be achieved:
只有在立即限制Lss的长度时,才能实现公平的枚举:
?- length(Lss,_), lists_concatenatedTails(Lss,[1,2,3]).
Lss = [[_G23, 1, 2, 3]] ;
Lss = [[_G26], [_G29, 1, 2, 3]] ;
Lss = [[_G26, 1], [_G32, 2, 3]] ;
Lss = [[_G26, 1, 2], [_G35, 3]] ;
Lss = [[_G26, 1, 2, 3], [_G38]] ;
Lss = [[_G29], [_G32], [_G35, 1, 2, 3]] ...
#1
You have the common predicate flatten/2
, which almost does the job:
你有共同的谓词flatten / 2,几乎完成了这项工作:
?- flatten([[1,2,3],[4,5,6],[7,8]], L).
L = [1, 2, 3, 4, 5, 6, 7, 8].
There are many implementations of flatten/2
available, just google it.
有很多flatten / 2可用的实现,只是google它。
If you know that the list of lists is not nested, you should rather use append/2
.
如果您知道列表列表未嵌套,则应使用append / 2。
Then, you need to drop the first element of each list before appending:
然后,您需要在追加之前删除每个列表的第一个元素:
list_tail([_|T], T).
Then:
?- maplist(list_tail, [[1,2,3],[4,5,6],[7,8]], T), append(T, L).
T = [[2, 3], [5, 6], [8]],
L = [2, 3, 5, 6, 8].
It might be a good exercise to take a more careful look at the implementation of append/2
linked above. With a small change in the definition (literally removing 1 character and adding 5) it will do the dropping and appending in the same step, without traversing the original list twice.
仔细研究上面链接的append / 2的实现可能是一个很好的练习。通过定义中的小变化(逐字地删除1个字符并添加5),它将执行删除并在同一步骤中追加,而不会遍历原始列表两次。
EDIT
So why is it that @repeat's initial solution does not terminate when the first argument is not a proper list, but the second is a proper list?
那么,为什么@ repeat的初始解决方案不会在第一个参数不是正确的列表时终止,但第二个是正确的列表?
nt_tails_append([[_|T]|Ls], As) :-
append(T, Ws, As),
nt_tails_append(Ls, Ws).
It is because when the first argument to nt_tails_append/2
is a free variable, the first two arguments to append/3
above are variables, too. When we call append/3
in this mode, we get, by definition:
这是因为当nt_tails_append / 2的第一个参数是一个*变量时,上面追加/ 3的前两个参数也是变量。当我们在这种模式下调用append / 3时,根据定义我们得到:
?- append(A, B, L).
A = [],
B = L .
In other words, the second and the third arguments are now unified. With the definition of nt_tail_append/2
, this means that the recursive call gets the same second argument as the original call, and a new free variable as the first argument. This is an endless loop, of course.
换句话说,第二个和第三个参数现在是统一的。通过定义nt_tail_append / 2,这意味着递归调用获得与原始调用相同的第二个参数,并将新的*变量作为第一个参数。当然,这是一个无限循环。
(Tellingly, if you care to look at the definition of append/2
linked above, you will see that the first argument must_be
a list
.)
(引人注目的是,如果你想看看上面链接的append / 2的定义,你会看到第一个参数must_be是一个列表。)
How does this help?
这有什么用?
tails_append(Ls, As) :-
maplist(list_tail, Ls, T),
append(T, As).
list_tail([_|T], T).
The way that maplist
is defined, all list arguments will be instantiated to proper lists. So you can safely use append/3
(here, used in the definition of append/2
).
定义maplist的方式,所有列表参数都将实例化为正确的列表。所以你可以安全地使用append / 3(这里,在append / 2的定义中使用)。
#2
Here is how you could do it using append/3
:
以下是使用append / 3的方法:
lists_concatenatedTails([],[]). lists_concatenatedTails([[_|Xs0]|Xss],Ys) :- append(Xs0,Ys0,Ys), lists_concatenatedTails(Xss,Ys0).
Sample query:
?- lists_concatenatedTails([[1,2,3],[4,5,6],[7,8]], Xs). Xs = [2, 3, 5, 6, 8].
Edit 2015-05-07
Note that the code that @Boris suggested (using list_tail/2
,maplist/3
,append/2
) also gives answers for the following query:
请注意,@ Boris建议的代码(使用list_tail / 2,maplist / 3,append / 2)也为以下查询提供了答案:
?- maplist(list_tail,Xss,Yss), append(Yss,[1,2,3]).
Xss = [[_G97, 1, 2, 3]], Yss = [[1, 2, 3]] ;
Xss = [[_G97], [_G106, 1, 2, 3]], Yss = [[], [1, 2, 3]] ;
Xss = [[_G97, 1], [_G106, 2, 3]], Yss = [[1], [2, 3]] ;
Xss = [[_G97, 1, 2], [_G106, 3]], Yss = [[1, 2], [3]] ;
Xss = [[_G97, 1, 2, 3], [_G106]], Yss = [[1, 2, 3], []] ;
Xss = [[_G97], [_G106], [_G115, 1, 2, 3]], Yss = [[], [], [1, 2, 3]] ...
This doesn't terminate universally---nor do we expect it to: the set of solutions is infinite in size and it can, in this case, only be covered by an infinite sequence of answers.
这并不是普遍终止的 - 我们也不期望它:解决方案集的大小是无限的,在这种情况下,它只能被无限的答案序列所覆盖。
In the following equivalent query lists_concatenatedTails/2
"loops" right away:
在以下等效查询中,lists_concatenatedTails / 2“循环”立即:
?- lists_concatenatedTails(Lss,[1,2,3]).
% not a single answer within finite time
Only when constraining the length of Lss
right away, fair enumeration can be achieved:
只有在立即限制Lss的长度时,才能实现公平的枚举:
?- length(Lss,_), lists_concatenatedTails(Lss,[1,2,3]).
Lss = [[_G23, 1, 2, 3]] ;
Lss = [[_G26], [_G29, 1, 2, 3]] ;
Lss = [[_G26, 1], [_G32, 2, 3]] ;
Lss = [[_G26, 1, 2], [_G35, 3]] ;
Lss = [[_G26, 1, 2, 3], [_G38]] ;
Lss = [[_G29], [_G32], [_G35, 1, 2, 3]] ...