我有这个谓词:
check_matrix([[_, E2, E3],
[E4, E5, E6],
[E7, E8, E9]]) :-
E5 = E9,
is_valid([E4, E5, E6]),
is_valid([E7, E8, R9]),
is_valid([E2, E5, E8]),
is_valid([E3, E6, E9]).
检查我的2 x 2矩阵是否有效,左上角的单元格_
被完全忽略。E2
,E3
,E4
和{{ 1}}单元格只是2 x 2矩阵的标题。
他们是E7
的更好的方式,我不需要拨打is_valid()
4次。如果矩阵变大,例如5x5,则该谓词需要调用is_valid()
10次。 Prolog这是正常的吗?或者他们是一个更优雅的方式来做到这一点?
我在想另一个谓词,它创建了我想传递给is_valid()
的所有可能列表的嵌套列表,并在每个列表上调用该谓词,然后将结果传递回{ {1}}。我觉得他们必须是一个更优雅的方式来做到这一点。任何建议,将不胜感激。
更新
is_valid()
只是一个对角线检查器,用于检查矩阵的对角线是否相同,如果不是,则谓词失败。
答案 0 :(得分:2)
如果你想避免使用这种硬编码的谓词,你可以尝试递归:
您检查每个列表中的is_valid
(第一个除外),以便您可以写:
check_matrix([H|T]) :- is_valid_each_list(T),....
is_vqlid_each_list([]).
is_vqlid_each_list([L|T]):- length(L,3),is_valid(L),
is_vqlid_each_list(T).
请注意,限制length(L,3)
表示元素是长度为3的列表(如果您愿意,则为任何参数K,只需添加其他参数)。
现在检查E2,E5,E8
(同一position > 1
中的元素):
is_valid_pos(L):-length(L,3), is_valid_pos(L,1).
is_valid_pos(_,4).
is_valid_pos(L,K):- findall(X,(member(L1,L),nth0(K,L1,X)),L2),
is_valid(L2),K1 is K+1, is_valid_pos(L,K1).
所以完整的通用解决方案:
check_matrix([H|T]) :- is_valid_each_list(T), is_valid_pos([H|T]).
is_vqlid_each_list([]).
is_vqlid_each_list([L|T]):- length(L,3),is_valid(L),
is_vqlid_each_list(T).
is_valid_pos(L):-length(L,3), is_valid_pos(L,1).
is_valid_pos(_,4).
is_valid_pos(L,K):- findall(X,(member(L1,L),nth0(K,L1,X)),L2),
is_valid(L2),K1 is K+1, is_valid_pos(L,K1).
答案 1 :(得分:2)
Prolog有一些像library(apply)
这样的库提供高阶谓词:谓词传递另一个谓词。
这里似乎适用的高阶谓词是maplist/2
。谓词将谓词(:Goal
)和列表(?List
)作为参数,并将:Goal
应用于?List
的元素,直到谓词失败,或列表为累。您可以将它与在迭代列表的命令式语言中的函数进行比较,并检查谓词是否适用于列表的所有成员。就像Python中的all(..)
一样。
因此,我们可以使用以下方法检查除第一行以外的所有:
:- use_module(library(apply)).
check_rows([_|T]) :-
maplist(is_valid,T).
然而,我们必须检查除第一列之外的所有列。因此,我们可以使用transpose/2
谓词。它需要两个参数,第二个参数是第一个参数的转置。所以:
?- transpose([[1, 2, 3],
| [4, 5, 6],
| [7, 8, 9]],X).
X = [[1, 4, 7], [2, 5, 8], [3, 6, 9]].
因此我们可以转置矩阵,然后再次使用maplist/2
来检查矩阵M
的转置的所有第一行。所以我们现在可以实现谓词:
:- use_module(library(apply)).
:- use_module(library(clpfd)).
check_matrix(M) :-
M = [_|MT],
maplist(is_valid,MT),
transpose(M,[_|TT]),
maplist(is_valid,TT).
修改强>:
如果你想检查除了第一个对角元素之外的所有元素,我建议定义两个额外的谓词:
all_same/1
检查列表中的所有元素是否相同;和diagonal/2
构建对角线元素列表。 all_same/1
可以实现为:
all_same([]).
all_same([_]).
all_same([H,H|T]) :-
all_same([H|T]).
和diagonal/2
可以通过以下方式获得:
diagonal(M,L) :-
diagonal(M,0,L).
diagonal([],_,[]).
diagonal([R|RT],I,[D|DT]) :-
nth0(I,R,D),
I1 is I+1,
diagonal(RT,I1,DT).
现在我们可以检查对角线如下:
check_matrix(M) :-
M = [_|MT],
maplist(is_valid,MT),
transpose(M,[_|TT]),
maplist(is_valid,TT),
diagonal(M,[_|DT]),
all_same(DT).