List 如何以正确的方式实现转置谓词(Prolog)?

List 如何以正确的方式实现转置谓词(Prolog)?,list,prolog,List,Prolog,我正在制作一个解决难题的程序。但是我需要做一个谓词,返回给定矩阵(列表列表)的转置,我不能使用预定义的。但是,无论我做什么,我都无法让谓词在不超过堆栈限制的情况下反向工作,例如: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

我正在制作一个解决难题的程序。但是我需要做一个谓词,返回给定矩阵(列表列表)的转置,我不能使用预定义的。但是,无论我做什么,我都无法让谓词在不超过堆栈限制的情况下反向工作,例如:
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吗?如果我给出了它的转置,你可以通过查看公开的、免费的(比如啤酒)开源SWI Prolog代码来重新组装谓词。为什么人们不经常这样做对我来说是个谜。这很容易,但我想还是比有人把工作代码扔给你更难

首先,这里是(有点神秘的):

这使用谓词
相同的长度/2
。它在中定义,如下所示:

same_length([], []).
same_length([_|T1], [_|T2]) :-
    same_length(T1, T2).
非常直截了当

然后它使用
maplist
foldl
。允许还是不允许?如果没有,您可以将
映射列表(长度(L),Ls)重写为:

all_same_length([], L).
all_same_length([X|Xs], L) :-
    same_length(X, L),
    all_same_length(Xs, L).
愚蠢的代码,不应该手动编写,但很好

然后,您可以将
地图列表(相同长度(L),Ls)
替换为
所有相同长度(L,Ls)

这就给您留下了
foldl(转置,L,Ts,[L | Ls],
。这是“神秘”的一点;这个限定可能是对作者的一种赞美

无论采用哪种方式,这样编写的忽略最后一个参数(结果)的折叠都可以作为循环重新编写,与上面的映射列表没有太大区别。折叠中使用的
transpose\u4
在其定义中有一个映射列表,但我已经展示了如何做到这一点

因为这看起来像是家庭作业,我会让你自己解决


作弊代码:如果你深入研究这个库的历史(都在github上!),你可能会非常幸运,找到一个相同转置的pre-foldl实现。

很多年前,我写了自己的转置/2,作为我工作的一部分。这是:

% 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]] 
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]]