如何实现正确的转置谓词(Prolog)?

时间:2019-03-15 21:02:10

标签: 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,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给列表?

2 个答案:

答案 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).

简单明了

然后,它使用maplistfoldl。是否允许?如果没有,您可以将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上!),您可能会非常幸运,并找到相同转置的折叠前实现。