我想在prolog
转置一个矩阵,例如
[[1,2,3],[1,2,3],[1,2,3]]应该成为
[[1,1,1],[2,2,2],[3,3,3]]
以下是我所做的:
%transpose(M,T)
transpose([],[]).
transpose(M,[H|T]):-row(H,M,M1),transpose(M1,T).
%row(H, M, M1).
row([],[],[]).
row([H|Tt] , [[H|T1]|T] , [T1|Z]) :- row(Tt,T,Z).
M
要转置T
的位置。
行谓词(不确定谓词和函数之间的差异)得到M中每个子列表的头部,因此我可以获得新的转置矩阵T
的整个第一行。
我分别测试了行,它给出了正确的结果。但是,当我尝试transpose
时,我只会错误地发现错误。没有任何反应,打印出新矩阵T
的信息。
任何人都可以帮助我吗?问题在于我构建程序的方式吗?或者我期望的结果确实只有true/false
,如果是这样,如何获得新矩阵?谢谢:))
答案 0 :(得分:2)
首先,关于术语的注释:函数的一个特征是每个输入与恰好一个输出相关。另一方面,关系可以适用于多个这样的组合。 Prolog谓词在他们的论点之间引发了关系,并且在回溯时会出现多个答案。
关于你的具体问题,@ lurker已经给出了一些可靠的建议。
然而,正如您已经注意到的,Prolog中的跟踪变得非常复杂,因此我想通过在Prolog中解释声明性调试的一些原则来补充潜伏者所写的内容。
从本质上讲,我们的目标是让我们的问题更简单而不是更难。我们从您为您发布的计划提及的案例开始:
?- transpose([[1,2,3],[1,2,3],[1,2,3]], Ls). false.
从逻辑上讲,关系太具体:失败在应该持有的情况下保留。
要找到此问题的原因,我们可以使用文本或图形跟踪器逐步完成精确的执行细节,并尝试跟踪所有细节。这非常困难,所以我建议您首先尝试找一个更简单的案例仍然失败。
我将通过概括查询来完成此操作。有几种方法可以做到这一点。例如,我可以使用 fresh 变量代替具体整数:
?- transpose([[_,_,_],[_,_,_],[_,_,_]], Ls). false.
啊哈,所以我们发现了一个更为笼统的案例仍然失败。只要这种情况失败,更具体的情况肯定也失败,因为我们推理的是纯和单调逻辑程序。 / p>
所以,新问题是:为什么这个更通用的查询失败了?为了找到原因,我们可以简单地进一步概括查询。例如,我们可以将此概括为以下情况,而不是推理每个包含3个元素的列表,其中两个列表被推广为“多个元素”:
?- transpose([[_|_],[_|_],[_,_,_]], Ls). false.
我们发现这个更通用的查询仍然失败。我们甚至可以进一步概括:
?- transpose([_,_,[_,_,_]], Ls). false.
此仍然失败!请注意,我们也可以把它放得太远。例如:
?- transpose([_,_,_], Ls). nontermination
在这里,我们遇到了一个完全不同的问题,与程序的终止属性有关。但是,在我们的案例中,我们希望找到意外失败的原因,因此我们回到上面的案例:
?- transpose([_,_,[_,_,_]], Ls). false.
此时,没有更多要概括,因此我们可以现在调用此简化查询的跟踪器。
但是,我们也可以继续朝不同的方向发展:并非每个测试用例都需要概括。我们还可以提出一个完全不同的情况,例如只有两个(而不是三个)元素的列表:
?- transpose([_,[_,_,_]], Ls). false
啊哈,所以这个也失败了,即使它应该成功!
即使是更简单的案例呢?
?- transpose([[_,_,_]], Ls). false.
进一步说:
?- transpose([[_,_]], Ls). false.
更进一步:
?- transpose([[_]], Ls). false.
这些查询的每个 应该成功,但失败。
要查找原因,请考虑基础逻辑程序的program-slicing。例如,让我们采取一个最简单的查询,我们发现应该成功,但不会:?- transpose([[_]], _).
我使用以下定义来概括原始程序的约束(=目标)
:- op(920,fy, *). *_.
例如,我们可以概括 row/3
,如下所示:
row([], [], []). row([H|Tt], [[H|T1]|T], [T1|Z]) :- *row(Tt,T,Z).
即使使用row/3
这个更为通用的版本,我们也会得到:
?- transpose([[_]], Ls). false.
这意味着:要使此查询成功,您必须在代码中添加其他子句(使其更通用)或更改剩余片段。< / p>
像潜伏者一样,我也将剩下的作为练习。
答案 1 :(得分:1)
Prolog只有谓词而不是功能。 谓词定义了一种关系,并且通常不被认为是&#34;做某事&#34;尽可能地定义一些东西。你的row/3
实际上定义了它的3个参数之间的关系。 3个参数的相关之处在于第1和第3个列表的元素是第2个列表的参数的头部和尾部。我将展示3个不同的查询,说明:
| ?- row([a,b,c], L, M).
L = [[a|A],[b|B],[c|C]]
M = [A,B,C]
yes
| ?- row(A, [[a,b,c],[d,e,f],[g,h,i]], L).
A = [a,d,g]
L = [[b,c],[e,f],[h,i]] ? ;
no
| ?- row(A, B, [[a,b],[c,d],[e,f]]).
A = [C,D,E]
B = [[C,a,b],[D,c,d],[E,e,f]] ? ;
no
| ?-
功能不会以这种方式运行。你也可以看到,知道这种关系,这个名字有点泛泛。 row
并未真正充分描述这种关系。也许它可以被称为heads_and_tails/3
,也许可以交换第一和第二个参数。
transpose/2
谓词失败的原因是它会递归到空列表列表(如果是3行矩阵,则为[[], [], []]
),但是transpose/2
个基数案例基于[]
。
<小时/> 让我们看看评论中建议的
transpose([], [])
的基本情况,代之以:
transpose([[] | _], []).
以下示例查询结果:
| ?- transpose([[a,b,c],[d,e,f]], T).
T = [[a,d],[b,e],[c,f]] ? ;
no
| ?- transpose([[a,b,c],[d,e,f], [a]], T).
no
| ?- transpose(T, [[a,b,c],[d,e,f]]).
T = [[a,d],[b,e|_],[c,f|_]] ? ;
no
第二个查询的结果不正确。根据此谓词的逻辑,解决此问题的一种方法是将基本案例从transpose([], [])
更改为此:
transpose(Empty, []) :- maplist(=([]), Empty).
这会导致谓词产生以下结果:
| ?- transpose(T, [[a,b,c],[d,e,f]]).
T = [[a,d],[b,e],[c,f]] ? a
no
| ?- transpose([[a,b,c],[d,e,f]], T).
T = [[a,d],[b,e],[c,f]] ? a
no
答案 2 :(得分:-1)
事实证明,之前的解决方案是不充分的,因为它只是对逻辑关系的描述。
除了关系规范之外,还需要对事实进行迭代,然后根据关系进行处理。
在以下程序中,foreach
用于生成事实。
在swipl上测试。
示例查询遵循该程序。
*/
(
program(INPUT_VECTOR,OUTPUT_VECTOR)
)
:-
(
(
(
INPUT_TRUTH_GOAL
)
=
(
item(INPUT_VECTOR,J_INDEX,K_INDEX,ITEM)
)
)
,
(
(
OUTPUT_TRUTH_GOAL
)
=
(
item(OUTPUT_VECTOR,K_INDEX,J_INDEX,ITEM)
)
)
,
(
(
nonvar(INPUT_VECTOR)
)
*->
(
once(foreach(INPUT_TRUTH_GOAL,OUTPUT_TRUTH_GOAL))
)
;
(
(
nonvar(OUTPUT_VECTOR)
)
*->
(
once(foreach(OUTPUT_TRUTH_GOAL,INPUT_TRUTH_GOAL))
)
)
)
)
.
(
item(VECTOR,J_INDEX,K_INDEX,ITEM)
)
:-
(
(
nth1(J_INDEX,VECTOR,SUBVECTOR)
)
,
(
nth1(K_INDEX,SUBVECTOR,ITEM)
)
)
.
/*
测试:
三个测试查询证明该程序基本适合:
?-
program([[1,2,3],[4,5,6],[7,8,9]],[[1,4,7],[2,5,8],[3,6,9]])
.
true.
?-
program([[1,2,3],[4,5,6],[7,8,9]],OUTPUT_VECTOR)
.
OUTPUT_VECTOR = [[1, 4, 7|_830], [2, 5, 8|_962], [3, 6, 9|_1100]|_356] .
?-
program(INPUT_VECTOR,[[1,4,7],[2,5,8],[3,6,9]])
.
INPUT_VECTOR = [[1, 2, 3|_560], [4, 5, 6|_626], [7, 8, 9|_698]|_350] .
?-
不幸的是,该计划未能通过坚定的测试:
?-
program(INPUT_VECTOR,OUTPUT_VECTOR)
,
INPUT_VECTOR = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
.
false .
?-