【问题标题】:; (or) operator in Prolog not returning true unless the left side is true, even if the right side of the operator returns true by itself; (或)Prolog 中的运算符不返回 true,除非左侧为 true,即使运算符的右侧本身返回 true
【发布时间】:2020-06-26 00:56:29
【问题描述】:

如果or 运算符两侧的两条规则中的任何一条在 Prolog 中成功,我将尝试返回 true。仅当发现 or 运算符左侧的内容为 true 时才有效。

看来我的代码应该按照http://www.cse.unsw.edu.au/~billw/dictionaries/prolog/or.html 工作。

Case2case1 被注释掉时有效,所以它应该返回true,但因为它在运算符的右侧,所以它不是。 (?)

为清楚起见,参数表示Person1Person2TypeOfCousinsTheyAreDegreesRemovedTheyAre。我正在尝试编写规则来确定两个人是否被一次性移除。

这是使用or 运算符的行,如果右侧为真,则不会返回true

cousins(A, B, 1, 1) :- ( cousinsCase1(A, B, 1, 1) ; cousinsCase2(A, B, 1, 1) ).

我尝试过的其他事情:

(1) 省略or 运算符并编写两个相同的函数,但每当调用它们并且顶部的函数失败时,我的程序就会崩溃。

cousins(A, B, 1, 1) :- var(FirstCousin),
                       cousin(A, FirstCousin, 1, 0),
                       parent(FirstCousin, B),
                       A \= B.

cousins(A, B, 1, 1) :-  var(P1),
                        parent(P1, A),
                        cousin(P1, B, 1, 0),
                        A \= B,
                        A \= P1,
                        B \= P1.

(2) 我也尝试过if-statement 来在第一个失败时调用另一个函数,但如果第一个案例再次失败,它会崩溃。

cousins(A, B, 1, 1) :- cousinsCase1(A, B, 1, 1) -> true ; cousinsCase2(A, B, 1, 1)).

如果第一个规则失败,是否有其他方法可以调用另一个规则?

编辑

根据给出的建议,这里有更多代码:

事实:

parent(gggm, ggm). 
parent(ggm, gm).
parent(gm, m).
parent(m, self).
parent(self, d).
parent(d, gd).
parent(gggm, gga).
parent(gga, c12a).
parent(c12a, c21a).
parent(c21a, c3).
parent(ggm, ga)
parent(ga, c11a).
parent(c11a, c2).
parent(gm, a).
parent(a, c1).
parent(m, s).
parent(s, n). 
parent(n, gn).
parent(c1, c11b).
parent(c11b, c12b).
parent(c2, c21b).
parent(c21b, c22).
parent(c3, c31).
parent(c31, c32).

我为使上述规则生效而编写的其他规则:

% Sibling Rule
sibling(A, B) :- parent(P, A), parent(P, B), A \= B.
% First-cousin Rule:
cousin(A, B, 1, 0) :- sibling(P1, P2), parent(P1, A), parent(P2, B).
% Second-cousin Rule:
cousin(A, B, 2, 0) :- parent(P1, A),
                      parent(P2, B),
                      parent(PP1, P1), % your grandparent
                      parent(PP2, P2), % your grand-aunt/uncle
                      sibling(PP1, PP2). % they're siblings
% 3rd-cousin and more Rule
cousin(A, B, M, 0) :- ReducedM = M - 1,
                      cousin(A, B, ReducedM, 0).

调用上述规则:旁注:两个调用都可以工作,但问题是让它们都工作而没有注释掉另一个规则:

表兄弟(self, c11b, 1, 1)。

此调用对应于第一个“1st-cousin, once-removed”案例,如果其他案例被注释掉,则该案例返回正确答案 true。

堂兄弟(self, c11a, 1, 1)。

此调用对应于第二个“1st-cousin, once-removed”案例,如果另一个案例被注释掉,则该案例返回正确答案 true。

【问题讨论】:

  • 问题显然出在代码的其他地方。 minimal reproducible example 可以澄清这里的事情......一次只关注一个错误。
  • cousins/2 谓词的两个子句中,目标var(FirstCousin)var(P1)总是为真,因为它们是子句正文中的第一个目标,而参数不是子句头部的变量。
  • 我正在考虑回答这个问题,但问题是我必须从头开始创作这么多的作品,因为你没有包含它,我不是在帮助你学习,而只是给你答案。我什至不知道你谓词中的数字是什么意思,代表人们关系的事实在哪里?
  • 另一件可以帮助您解决问题的方法是使用测试用例。我目前的信念是您的表亲/ 4 谓词中的一个或两个是错误的。如果您有测试用例并分别测试每个用例,那么您将知道是否是那些谓词抛出了逻辑。仅仅因为你学会了使用 ;/2 并不意味着你用错了,这是你应该关注的。但正如我所指出的,您在问题中遗漏了很多内容,我只能猜测。
  • 感兴趣的:Cousin tree

标签: prolog or-operator


【解决方案1】:

这是答案中的评论,因为它在评论中的格式不正确。

大多数Prolog初学者没有足够早意识到的是Prolog是基于逻辑的(他们意识到),逻辑andornot这三个基本运算符是Prolog中的运算符,即(, ; \+)。它没有意识到这些运算符的真正含义。


not 开头,在Prolog 中使用not/1,但现在通常为(\+)/1

?- \+ false.
true.

?- \+ true.
false.

或使用较旧的not/1,您可以使用它,但就像在莎士比亚戏剧中讲话一样,因为它不再以这种方式进行。我将其包含在此处是因为许多较旧的示例仍然以这种方式包含在示例中。

?- not(true).
false.

?- not(false).
true.

接下来是and,在Prolog中是,/2

许多 Prolog 新用户不将其视为 logical and 的原因是,许多其他编程语言中的 , 被视为语句分隔符 (Ref),其作用类似于英文句子。在编程中低估, 的整个问题在于它实际上是一个运算符,并且用于许多事情,程序员甚至没有意识到它应该几乎总是被认为是一个运算符,但具有许多不同的含义,(运算符超载)。此外,因为, 用作语句分隔符,语句通常放在单独的行上,一些程序员甚至认为逗号 (,) 只是语句结束,就像句点 (.) 是行结束造句;这不是考虑这些单字符运算符的方式。他们是运营商,需要被这样看待和理解。

既然您知道导致问题的想法来自何处以及如何产生,那么下次您在编程语言中看到逗号, 或句点. 时,您真的需要花时间思考它的含义.

?- true,true.
true.

?- true,false.
false.

?- false,true.
false.

?- false,false.
false.

最后是合乎逻辑的,或者在 Prolog 中是 ;/2 或在 DCG 中将显示为 |/2。 DCG中|/2的使用与BNF中的|相同。

?- true;true.
true ;
true.

?- true;false.
true ;
false.

?- false;true.
true.

?- false;false.
false.

关于在 Prolog 中使用 or (;) 的结果需要注意的一个有趣的事情是,当命题之一为真时,它们将返回真值,只有当所有命题都为假时,它们才会返回. (不确定命题是否是此处使用的正确词)。例如

?- false;false;false.
false.

?- false;false;true.
true.

?- true;false;true.
true ;
true.

?- true;true;true.
true ;
true ;
true.

如果你没有注意我的警告,当你看到他们时要考虑运营商,你们有多少人看了

?- true,true.
true.

并且没想到这通常会在源代码中写成

true,
true.

, 看起来像一个语句结束。 , 不是语句结束,它是 logical and 运算符。所以帮自己一个忙,即使是单个,,也要非常挑剔,因为它在编程中具有特定的含义。

理解这个想法的相反方法是使用加法运算符 (+),就像语句结束运算符一样,但对于数学新手来说,可能会被错误地认为是在重新格式化一个简单的数学表达式。

A =
1 +
2 +
3

这不是人们习惯于看到一个简单的数学表达式的方式,而是一些程序员看待, 运算符的使用方式。

多年来,我看到的一件事将容易获得这一点的程序员与在他们所有的职业生涯中苦苦挣扎的程序员区分开来,那些在parsing 课程中表现出色的人很容易获得这一点,因为他们必须向下解析语法到,等标记,然后将其转换为语言的semantics

有关详细信息,请参阅1.2 节。控制paper第23页。


编辑

您确实需要使用测试用例。这里有两个可以帮助您入门。

这是使用 SWI-Prolog 完成的

:- begin_tests(family_relationship).

sibling_test_case_generator(ggm ,gga ).
sibling_test_case_generator(gga ,ggm ).
sibling_test_case_generator(gm  ,ga  ).
sibling_test_case_generator(ga  ,gm  ).
sibling_test_case_generator(m   ,a   ).
sibling_test_case_generator(a   ,m   ).
sibling_test_case_generator(self,s   ).
sibling_test_case_generator(s   ,self).

test(01,[forall(sibling_test_case_generator(Person,Sibling))]) :-
    sibling(Person,Sibling).

cousin_1_0_test_case_generator(gm  ,c12a).
cousin_1_0_test_case_generator(ga  ,c12a).
cousin_1_0_test_case_generator(m   ,c11a).
cousin_1_0_test_case_generator(a   ,c11a).
cousin_1_0_test_case_generator(self,c1  ).
cousin_1_0_test_case_generator(s   ,c1  ).
cousin_1_0_test_case_generator(d   ,n   ).
cousin_1_0_test_case_generator(c12a,gm  ).
cousin_1_0_test_case_generator(c12a,ga  ).
cousin_1_0_test_case_generator(c11a,m   ).
cousin_1_0_test_case_generator(c11a,a   ).
cousin_1_0_test_case_generator(c1  ,self).
cousin_1_0_test_case_generator(c1  ,s   ).
cousin_1_0_test_case_generator(n   ,d   ).

test(02,[nondet,forall(cousin_1_0_test_case_generator(Person,Cousin))]) :-
    cousin(Person, Cousin, 1, 0).

:- end_tests(family_relationship).

编辑

作者:J DiVector:Matt Leidholm (LinkTiger) - 自己的作品基于:Cousin tree.png,公共领域,Link

【讨论】:

    【解决方案2】:

    这是一个答案。

    根据您在问题中给出的内容和如下所述的一些更改使用此代码,此代码有效。由于您没有提供测试用例,我不确定答案是否符合您的期望或需要。

    parent(gggm, ggm).
    parent(ggm, gm).
    parent(gm, m).
    parent(m, self).
    parent(self, d).
    parent(d, gd).
    parent(gggm, gga).
    parent(gga, c12a).
    parent(c12a, c21a).
    parent(c21a, c3).
    parent(ggm, ga).
    parent(ga, c11a).
    parent(c11a, c2).
    parent(gm, a).
    parent(a, c1).
    parent(m, s).
    parent(s, n).
    parent(n, gn).
    parent(c1, c11b).
    parent(c11b, c12b).
    parent(c2, c21b).
    parent(c21b, c22).
    parent(c3, c31).
    parent(c31, c32).
    
    % Sibling Rule
    sibling(A, B) :-
        parent(P, A),
        parent(P, B),
        A \= B.
    
    % First-cousin Rule:
    cousin(A, B, 1, 0) :-
        sibling(P1, P2),
        parent(P1, A),
        parent(P2, B).
    
    % Second-cousin Rule:
    cousin(A, B, 2, 0) :-
        parent(P1, A),
        parent(P2, B),
        parent(PP1, P1), % your grandparent
        parent(PP2, P2), % your grand-aunt/uncle
        sibling(PP1, PP2). % they're siblings
    
    % 3rd-cousin and more Rule
    cousin(A, B, M, 0) :-
        % ReducedM = M - 1,
        ReducedM is M - 1,
        ReducedM > 0,
        cousin(A, B, ReducedM, 0).
    
    cousinsCase1(A, B, 1, 1) :-
        % var(FirstCousin),
        cousin(A, FirstCousin, 1, 0),
        parent(FirstCousin, B),
        A \= B.
    
    cousinsCase2(A, B, 1, 1) :-
        % var(P1),
        parent(P1, A),
        cousin(P1, B, 1, 0),
        A \= B,
        A \= P1,
        B \= P1.
    
    cousins(A, B, 1, 1) :-
        (
            cousinsCase1(A, B, 1, 1)
        ;
            cousinsCase2(A, B, 1, 1)
        ).
    

    正如 Paulo 所指出的,第一个更改是对 var/2 的检查被注释掉了。

    接下来的更改是将= 更改为is

    停止无限循环的第三个更改是添加ReducedM > 0,

    此查询现在运行。

    ?- cousins(Person,Cousin,1,1).
    Person = gm,
    Cousin = c21a ;
    Person = ga,
    Cousin = c21a ;
    Person = m,
    Cousin = c2 ;
    Person = a,
    Cousin = c2 ;
    Person = self,
    Cousin = c11b ;
    Person = s,
    Cousin = c11b ;
    Person = d,
    Cousin = gn ;
    Person = c12a,
    Cousin = m ;
    Person = c12a,
    Cousin = a ;
    Person = c12a,
    Cousin = c11a ;
    Person = c11a,
    Cousin = self ;
    Person = c11a,
    Cousin = s ;
    Person = c11a,
    Cousin = c1 ;
    Person = c1,
    Cousin = d ;
    Person = c1,
    Cousin = n ;
    Person = n,
    Cousin = gd ;
    Person = m,
    Cousin = c12a ;
    Person = self,
    Cousin = c11a ;
    Person = d,
    Cousin = c1 ;
    Person = gd,
    Cousin = n ;
    Person = c21a,
    Cousin = gm ;
    Person = c21a,
    Cousin = ga ;
    Person = c11a,
    Cousin = c12a ;
    Person = c2,
    Cousin = m ;
    Person = c2,
    Cousin = a ;
    Person = a,
    Cousin = c12a ;
    Person = c1,
    Cousin = c11a ;
    Person = s,
    Cousin = c11a ;
    Person = n,
    Cousin = c1 ;
    Person = gn,
    Cousin = d ;
    Person = c11b,
    Cousin = self ;
    Person = c11b,
    Cousin = s ;
    false.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-28
      • 2015-05-19
      • 1970-01-01
      • 2023-02-22
      • 1970-01-01
      • 1970-01-01
      • 2023-03-07
      相关资源
      最近更新 更多