我正在编写一个解决难题的程序。但是我需要做一个谓词,在给定一个矩阵(列表列表)的情况下返回转置,而我不能使用预定义的。但是我做任何事都不能使谓词向后工作而不超出堆栈限制,例如:trans([[1,2],[3,4]],X).
返回[[1,3],[2,4]]
但trans(X,[[1,3],[2,4]]).
超过了堆栈限制。
这是反谓词:
trans(M,M1):-
length(M,L),
trans1(0,L,M,R).
trans1(N,N,_,[]).
trans1(I,N,M,M1):-
I1 is I+1,
column(M,I1,C),
trans1(I1,N,M,M2).
这是我使用的列谓词:
row([H|_],1,H):-!.
row([_|T],I,X) :-
I1 is I-1,
row(T,I1,X).
column([],_,[]).
column([H|T], I, [R|X]):-
row(H, I, R),
column(T,I,X).
有任何想法,如果我给它换位,我怎么能使用trans给列表?
答案 0 :(得分:1)
很多年前,我写了自己的transpose / 2,作为我IL project的一部分。在这里:
% row/columns transposition
%
transpose_col_row([], []).
transpose_col_row([U], B) :- gen(U, B).
transpose_col_row([H|T], R) :- transpose_col_row(T, TC), splash(H, TC, R).
gen([H|T], [[H]|RT]) :- gen(T,RT).
gen([], []).
splash([], [], []).
splash([H|T], [R|K], [[H|R]|U]) :-
splash(T,K,U).
尽管代码没有使用任何复杂的东西,要理解它的作用并不容易,并且像您自己的SWI-Prolog库(clpfd)实现一样,它也不是“可逆的”。
您的代码有很多问题需要解决(注意:单例警告确实是错误),但是假设您可以确定它们并获得有效的trans(M,T),则可以使用简单的“ hack” ,在检查实例化之后交换参数:
trans_rev(M,T) :- var(M) -> trans(T,M) ; trans(M,T).
让我们尝试一下我自己的实现,即
transpose_col_row_rev(M,T) :-
var(M) -> transpose_col_row(T,M) ; transpose_col_row(M,T).
?- transpose_col_row_rev([[1,2]],T).
T = [[1], [2]]
?- transpose_col_row_rev(M,$T).
M = [[1, 2]],
T = [[1], [2]]
答案 1 :(得分:0)
您可以通过查看公开的免费(如啤酒)开源SWI-Prolog代码来重新组合谓词。人们为什么不经常这样做,这对我来说还是个谜。这很容易,但比我想将工作代码转储给您的人还要困难。
首先,这是{有点神秘} implementation of transpose/2
in library(clpfd):
lists_transpose([], []).
lists_transpose([L|Ls], Ts) :-
maplist(same_length(L), Ls),
foldl(transpose_, L, Ts, [L|Ls], _).
transpose_(_, Fs, Lists0, Lists) :-
maplist(list_first_rest, Lists0, Fs, Lists).
list_first_rest([L|Ls], L, Ls).
这使用谓词same_length/2
。它在library(lists)中定义,如下所示:
same_length([], []).
same_length([_|T1], [_|T2]) :-
same_length(T1, T2).
简单明了
然后,它使用maplist
和foldl
。是否允许?如果没有,您可以将maplist(same_length(L), Ls)
重写为:
all_same_length([], L).
all_same_length([X|Xs], L) :-
same_length(X, L),
all_same_length(Xs, L).
不应该手动编写的愚蠢代码。
然后可以将maplist(same_length(L), Ls)
替换为all_same_length(Ls, L)
。
这使您拥有foldl(transpose_, L, Ts, [L|Ls], _)
。这是“神秘的”位;这种资格也许是对写它的人的一种称赞。
无论哪种方式,这样编写的忽略最后一个参数(结果)的折叠都可以重写为与上面的maplist不太相似的循环。折叠中使用的transpose_/4
的定义中包含一个地图列表,但是我已经展示了如何做到这一点。
因为这看起来像是作业,所以我会让你自己弄清楚。
作弊代码:如果您对库的历史有足够的了解(全部在github上!),您可能会非常幸运,并找到相同转置的折叠前实现。