【问题标题】:Simple prolog program returns false too early简单的 prolog 程序过早返回 false
【发布时间】:2013-12-01 21:26:02
【问题描述】:

我已经有一段时间没有在 Prolog 中编程了。今天,我试着做一个简单的程序。它列出了谁属于同一个家庭的一些事实。如果两个人属于同一个家庭,他们不能互相赠送礼物。我想让所有人(或至少一个人)允许某人送礼。

family(john, jack).
family(matt, ann).
family(ann, jack).
family(jordan, michael).
family(michael, liz).

sameFamily(X, Y) :-
  family(X, Y).
sameFamily(X, X) :-
  false.
sameFamilySym(X, Y) :-
  sameFamily(X, Y).
sameFamilySym(X, Y) :-
  sameFamily(Y, X).
sameFamilyTrans(X, Z) :-
  sameFamilySym(X, Y),
  sameFamilySym(Y, Z).

gift(X, Y) :-
  not(sameFamilyTrans(X, Y)).

如果sameFamilyTrans/2 返回false 的一些查询实际上应该返回true

sameFamilyTrans/2 显然是错误的。我想我需要保留一个中间传递性列表。像这样的:

sameFamilyTrans(X, Z, [Y|Ys]) :-
  sameFamilySym(X, Y, []),
  sameFamilyTrans(Y, Z, Ys).

但是我不知道怎么称呼它。

附注我正在使用 SWI-Prolog,如果这有什么不同的话。

【问题讨论】:

    标签: prolog


    【解决方案1】:

    是的,你在正确的轨道上。诀窍是用空累加器调用传递闭包,并在每个步骤中检查是否找到循环(即,我们以前是否见过这个家庭成员。正如“假”所指出的那样,这些人需要是不过,在进入 not 之前已经实例化了。

    总之,这是可行的:

    family(john, jack).
    family(matt, ann).
    family(ann, jack).
    family(jordan, michael).
    family(michael, liz).
    
    sameFamily(X, Y) :-
      family(X, Y).
    sameFamilySym(X, Y) :-
      sameFamily(X, Y).
    sameFamilySym(X, Y) :-
      sameFamily(Y, X).
    
    sameFamilyTrans(X, Y, Acc) :-
      sameFamilySym(X, Y),
      not(member(Y,Acc)).
    
    sameFamilyTrans(X, Z, Acc) :-
      sameFamilySym(X, Y),
      not(member(Y,Acc)),
      sameFamilyTrans(Y, Z, [X|Acc]).
    
    person(X) :- family(X, _).
    person(X) :- family(_, X).
    
    gift(X, Y) :-
      person(X),
      person(Y),
      X \= Y,
      not(sameFamilyTrans(X, Y, [])).
    

    一点背景知识:传递闭包实际上不是一阶可定义的(参见https://en.wikipedia.org/wiki/Transitive_closure#In_logic_and_computational_complexity)。所以可以预料这会有点棘手。

    【讨论】:

      【解决方案2】:

      否定在 Prolog 中以非常基本的方式实现。只有当否定查询被充分实例化时,您才能从本质上得到有用的答案。为此,请定义一个关系 person/1 来描述您正在考虑的所有人员。然后你可以写:

      gift(X,Y) :-
         person(X),
         person(Y),
         \+ sameFamily(X,Y).
      

      sameFamily/2 的定义还有另一个问题。

      【讨论】:

      • 感谢您的回答。我查看了sameFamily/2 的定义,虽然它显然是错误的,但我还没有找到我的错误。你能指出我正确的方向吗?我已经为它写了一个新的定义并更新了我的问题。
      • @RaptorDotCpp:总是比较一组解决方案:setof(A-B,samf(A,B),ABs) 找到所有解决方案了吗?
      • 找到了所有正确的解决方案,但也找到了其他解决方案。那些不应该在那里。
      • @RaptorDotCpp: sameFamilyTrans(X,Y) 失败。
      • 我知道,但我不明白为什么。我是否需要以某种方式查询中间传递性?我该怎么做?我的问题中的新代码之类的东西?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-05
      • 2017-03-24
      • 1970-01-01
      • 1970-01-01
      • 2021-12-20
      相关资源
      最近更新 更多