Prolog:试图解决一个难题!返回错误

Prolog: Trying to solve a puzzle! returned false

我 post 末尾的代码应该可以回答以下难题:

Brown, Clark, Jones and Smith are 4 substantial citizens who serve their community as achitect, banker, doctor and lawyer, though not necessarily respectively. Brown, who is more conservative than Jones but more liberal than Smith, is a better golfer than the men who are YOUNGER than he is and has a larger income than the men who are OLDER than Clark. The banker, who earns more than the architect, is neither the youngest nor the oldest.

The doctor, who is a poorer golfer than the lawyer, is less conservative than the architect. As might be expected, the oldest man is the most conservative and has the largest income, and the youngest man is the best golfer. What is each man's profession?

代码:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% We represent each "person" with a six-tuple of the form
%
% [ name , profession , age , income , politics , golf ranking ]
%
% where name is either brown, clark, jones, or smith
%       profession is either banker, lawyer, doctor, or architect
%       age is a range 1 .. 4, with 1 being the youngest and 4 the oldest
%       income is a range 1 .. 4, with 1 being the least and 4 the most
%       politics is a range 1 .. 4, with 1 being conservative, 4 liberal
%       golf ranking is a range 1 .. 4, 1 for the best rank, 4 for the worst
%
:- use_module(library(clpfd)).
solutions(L) :- L = [ [brown, _, _, _, _, _], [clark, _, _, _, _, _],
                      [jones, _, _, _, _, _], [smith, _, _, _, _, _] ],
                clue1(L),
                clue2(L),
                clue3(L),
                clue4(L),
                constrained_profession(L),
                constrained_age(L),
                constrained_income(L),
                constrained_politics(L),
                constrained_golf_rank(L).

%
% clue #1
% brown, who is more conservateive than jones but
% more liberal than smith, is a better golfer than
% the men who are younger than he is and has a larger
% income than the men who are older than clark
%

clue1(L) :- member(P1,L), member(P2,L), member(P3,L),
            P1 = [brown, _, A1, _, L1, G1],
            P2 = [jones, _, _, _, L2, _],
            P3 = [smith, _, _, _, L3, _],
            liberaler( P2, P1 ),
            liberaler( P1, P3 ),
            not( clue1_helper_a(L) ),
            not( clue1_helper_b(L) ).

% for all men younger than brown he is a better golfer ===>
% it is not the case that there exists a man younger than brown
% such that brown is not a better golfer than him.
% The "is not the case" is taken care of in clue1.

clue1_helper_a(L) :- member(P1,L), P1 = [brown, _, A1, _, L1, G1],
                     member(PU,L), PU = [_, _, AU, _, _, GU],
                     younger(PU,P1),
                     not(golfier(P1, PU)).

% for all men older than clark, brown makes more money than they do ===>
% it is not the case that there exists a man older than clark such that
% brown does not make more money than him.
% The "is not the case" is taken care of in clue1.

clue1_helper_b(L) :- member(P1,L), P1 = [brown, _, _, _, _, _],
                     member(P2,L), P2 = [clark, _, _, _, _, _],
                     member(PU,L), PU = [_, _, _, _, _, _],
                     younger(P2,PU),
                     not(richer(P1, PU)).

%
% clue #2
% the banker, who earns more than the archiect, is
% neither the youngest nor the oldest
%

clue2(L) :- member(P1,L), member(P2,L),
            P1 = [_, banker, A1, I1, _, _],
            P2 = [_, architect, _, I2, _, _],
            richer(P1,P2),
            not( A1 = 1 ),
            not( A1 = 4 ).

%
% clue #3
% the doctor, who is a pooer golfer than the lawyer, is
% less conservative than the architect. 
%

clue3(L) :- member(P1, L), member(P2, L), member(P3,L),
            P1 = [_,doctor, _, _, L1, G1],
            P2 = [_,lawyer, _, _, _, G2],
            P3 = [_,architect, _, _, L3, _],
            golfier(P2,P1),
            liberaler(P1,P3).

%
% clue #4
% as might be expected, the oldest man is the most
% conservative and has the largest income, and the 
% youngest man is the best golfer.

clue4(L) :- member(P1,L), member(P2,L),
            P1 = [_, _, 4, 4, 1, _],
            P2 = [_, _, 1, _, _, 1].

%
% relations
%

younger(X,Y) :- X = [_, _, AX, _, _, _], Y = [_, _, AY, _, _, _], AX #< AY.

liberaler(X,Y) :- X = [_, _, _, _, LX, _], Y = [_, _, _, _, LY, _], LX #> LY.

golfier(X,Y) :- X = [_, _, _, _, _, GX], Y = [_, _, _, _, _, GY], GX #< GY.

richer(X,Y) :- X = [_, _, _, IX, _, _], Y = [_, _, _, IY, _, _], IX #> IY.

%
% constraints
%

constrained_profession(L) :-
    member(P1,L), member(P2,L), member(P3,L), member(P4,L),
    P1 = [_, banker, _, _, _, _],
    P2 = [_, lawyer, _, _, _, _],
    P3 = [_, doctor, _, _, _, _],
    P4 = [_, architect, _, _, _, _].

constrained_age(L) :-
    member(P1,L), member(P2,L), member(P3,L), member(P4,L),
    P1 = [_, _, 1, _, _, _],
    P2 = [_, _, 2, _, _, _],
    P3 = [_, _, 3, _, _, _],
    P4 = [_, _, 4, _, _, _].

constrained_income(L) :-
    member(P1,L), member(P2,L), member(P3,L), member(P4,L),
    P1 = [_, _, _, 1, _, _],
    P2 = [_, _, _, 2, _, _],
    P3 = [_, _, _, 3, _, _],
    P4 = [_, _, _, 4, _, _].

constrained_politics(L) :-
    member(P1,L), member(P2,L), member(P3,L), member(P4,L),
    P1 = [_, _, _, _, 1, _],
    P2 = [_, _, _, _, 2, _],
    P3 = [_, _, _, _, 3, _],
    P4 = [_, _, _, _, 4, _].

constrained_golf_rank(L) :-
    member(P1,L), member(P2,L), member(P3,L), member(P4,L),
    P1 = [_, _, _, _, _, 1],
    P2 = [_, _, _, _, _, 2],
    P3 = [_, _, _, _, _, 3],
    P4 = [_, _, _, _, _, 4].

% end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

可是,当我运行它的时候,它returns假的!

?- solutions(L).
false.

有人可以帮帮我吗?

我不会为您解决整个问题,但我想解释一个通用方法,让您快速缩小此类问题的范围。

回顾一下,我们有以下主要谓词:

solutions(L) :-
        L = [ [brown, _, _, _, _, _], [clark, _, _, _, _, _],
              [jones, _, _, _, _, _], [smith, _, _, _, _, _] ],
        clue1(L),
        clue2(L),
        clue3(L),
        clue4(L),
        constrained_profession(L),
        constrained_age(L),
        constrained_income(L),
        constrained_politics(L),
        constrained_golf_rank(L).

意外失败,即使对于最一般的查询,其中所有参数都是新变量:

?- solutions(L).
false.

为什么会失败?正如在 GUPU 中一样,我将使用 ,通过使用以下定义来 概括掉 目标:

:- op(950, fy, *).
*_.

如果你在你的程序中包含这个,你可以在目标前使用 (*)/1 到 "strike them out"。这最多可以使生成的程序更通用

例如,让我们现在概括掉 所有 个目标(我使用 strikeout 文本来表示一个目标不再限制解决方案,因为它被概括掉了):

solutions(L) :-
        * L = [ [brown, _, _, _, _, _], [clark, _, _, _, _, _],    [jones, _, _, _, _, _], [smith, _, _, _, _, _] ],
        * clue1(L),
        * clue2(L),
        * clue3(L),
        * clue4(L),
        * constrained_profession(L),
        * constrained_age(L),
        * constrained_income(L),
        * constrained_politics(L),
        * constrained_golf_rank(L).

现在查询成功:

?- solutions(L).
true.

但是,现在的程序显然过于笼统。现在重点是:我们可以有选择地重新引入目标 (= constraints) 来定位导致程序意外失败的错误。

例如,我选择第一个目标和clue2/1个目标,并删除它们前面的(*)/1

solutions(L) :-
        L = [ [brown, _, _, _, _, _], [clark, _, _, _, _, _],
              [jones, _, _, _, _, _], [smith, _, _, _, _, _] ],
        * clue1(L),
        clue2(L),
        * clue3(L),
        * clue4(L),
        * constrained_profession(L),
        * constrained_age(L),
        * constrained_income(L),
        * constrained_politics(L),
        * constrained_golf_rank(L).

现在,我们又有了:

?- solutions(L).
false.

由此可知clue2/1一定有错误。这是因为任何进一步的目标最多只能使谓词更加具体,并且它们无法消除该目标的失败。

让我们重新考虑clue2/1的定义:


clue2(L) :- member(P1,L), member(P2,L),
            P1 = [_, banker, A1, I1, _, _],
            P2 = [_, architect, _, I2, _, _],
            richer(P1,P2),
            not( A1 = 1 ),
            not( A1 = 4 ).

这里的错误是在使用 非单调 谓词 not/1 时,不正确地 删除了这种情况下的解决方案。检查一下,即使对于非常一般的查询,我们也不会从这个谓词中得到任何答案:

?- length(Ls, 4), clue2(Ls).
false.

怎么办?答案:

Instead of not/1 or (\+)/1, use constraints to express disequalities.

约束是真实的关系,可以在所有方向上使用,即使它的部分或全部参数是自由变量!

在您的情况下,使用 dif/2 或在本例中使用 CLP(FD) 约束 (#\=)/2 来表示两个整数更好不同:

clue2(L) :-
        member(P1,L), member(P2,L),
        P1 = [_, banker, A1, I1, _, _],
        P2 = [_, architect, _, I2, _, _],
        richer(P1,P2),
        A1 #\= 1,
        A1 #\= 4.

通过这个简单的更改,谓词现在会产生答案,并且缩小程序 成功 最一般的查询。

通过系统地应用这种 声明式调试 技术,您可以更正其他谓词中的剩余错误。我把它留作练习。