阻止Prolog推断值

时间:2018-12-27 15:52:44

标签: prolog clpfd

如果我运行solved([[x, o, o], [o, o, o], [o, o, o]]),则应该输出true,因为只有x;如果我运行solved([[x, o, o], [o, o, o], [o, o, x]]),则应该输出false,因为存在多个x。但是,运行它会一直输出true,因为它会推断出C的值。

:- use_module(library(clpfd)).

rotate_clock(Xss, Zss) :-
   transpose(Xss, Yss),
   maplist(reverse, Yss, Zss).

rotate_anti(Xss, Zss) :-
   maplist(reverse, Xss, Yss),
   transpose(Yss, Zss).

linjmp([x, x, o | T], [o, o, x | T]).
linjmp([o, x, x | T], [x, o, o | T]).
linjmp([H|T1], [H|T2]) :- linjmp(T1,T2).

horizjmp([A|T],[B|T]) :- linjmp(A,B).
horizjmp([H|T1],[H|T2]) :- horizjmp(T1,T2).

jump(B,A) :- horizjmp(B,A).
jump(B,A) :- rotate_clock(B,BR), horizjmp(BR,BRJ), rotate_anti(BRJ, A).

num_x(A, C) :- count(A, x, C).

count([],X,0).
count([X|T],X,Y):- count(T,X,Z), Y is 1+Z.
count([_|T],X,Z):- count(T,X,Z).

sum_list([], 0).
sum_list([H|T], Sum) :-
   sum_list(T, Rest),
   Sum is H + Rest.

solved(A) :-
   maplist(num_x, A, B),
   sum_list(B, C),
   C == 1.

1 个答案:

答案 0 :(得分:2)

与其尝试更改一种语言的行为(虽然有可能,但当然是一个挑战),不如调查为什么最终Prolog用C找到一个C == 1可能更好。如果我们自己评估maplist(num_x, A, B),我们会看到:

?- maplist(num_x, [[x, o, o], [o, o, o], [o, o, x]], B).
B = [1, 0, 1] ;
B = [1, 0, 0] ;
B = [0, 0, 1] ;
B = [0, 0, 0].

因此,num_x/2谓词似乎可以为同一列表生成多个结果:对于具有一个x的列表,它首先生成1,然后生成{{1 }}。

如果我们对0做一些测试,可以确认这一点:

count/3

因此,看来?- count([x, o, o], x, C). C = 1 ; C = 0. ?- count([x, x, o], x, C). C = 2 ; C = 1 ; C = 1 ; C = 0. 每次都有一个回溯点,可以决定是否计算给定的count/3

实际上,如果我们看一下x谓词,就会看到:

count/3

因此,对于非空列表,这里有两种方式子句:一种子句的头等于count([],X,0). count([X|T],X,Y):- count(T,X,Z), Y is 1+Z. count([_|T],X,Z):- count(T,X,Z).,我们要计数的元素,在这种情况下为X,但最后一种子句说,无论head的值是多少,Prolog都不会计算该元素。 Prolog执行回溯,因此最终将同时选择这两个子句。

我们可以添加dif/2来添加约束,要求head和Y is 1+Z应该是 dif ferrent,例如:

X

现在,如果列表中出现count([],X,0). count([X|T],X,Y):- count(T,X,Z), Y is 1+Z. count([H|T],X,Z):- dif(H, X), count(T,X,Z).,我们将对该元素进行计数。