【问题标题】:Solving mutually recursive constraints in Prolog在 Prolog 中解决相互递归的约束
【发布时间】:2016-07-22 20:11:38
【问题描述】:

我正在尝试使用 SWI-Prolog 解决一些相互递归的约束。这些约束相对简单,但查询这些谓词中的任何一个都会导致无限递归:

%If X is an animal, then X is a bird or a mammal, and vice-versa.
animal(X) :- 
    (mammal(X);bird(X)),
    (male(X);female(X)).

male(X) :- animal(X).
female(X) :- animal(X).

bird(X) :- (X='parrot';X='pigeon'),animal(X).

mammal(X) :- (X='cat';X='dog'),animal(X).

是否可以在 Prolog 中解决这些约束而不使它们成为非递归的?

我用几个基本情况编写了一个类似的程序,但是查询mammal(X),bird(X) 仍然导致无限递归而不是返回false

%If X is an animal, then X is a bird or a mammal, and vice-versa.
animal(X) :- 
    (mammal(X);bird(X)).

bird('parrot').
bird('pigeon').
bird(X) :- (X='parrot';X='pigeon'),animal(X).

mammal('cat').
mammal('dog').
mammal(X) :- (X='cat';X='dog'),animal(X).

【问题讨论】:

  • 您意识到 prolog 谓词不会像函数那样返回值,对吧?所以dif(mammal(X), bird(X)) 并没有像你认为的那样做。事实上,它总是会成功,因为mammal(X)bird(X) 对于任何X 而言总是必然不同。正如斯科特在他的“回答”中指出的那样,您没有任何事实或基本案例。
  • @lurker 是的,dif/2 谓词在这种情况下是多余的。我编辑了程序来纠正这个问题。
  • 它们不仅仅是多余的。他们被错误地使用了。 :p 您现有的逻辑,除了斯科特指出的缺少基本情况外,是循环的。 animal/1 定义为 lf male/1female/1mammal/1。而male/1female/1mammal/1是根据animal/1定义的。
  • @lurker 我再次更新了问题,即使添加了几个基本案例,我也遇到了同样的问题。
  • 新逻辑仍然循环。 mammal 根据animal 定义,animal 根据mammal 定义。

标签: recursion prolog constraint-programming


【解决方案1】:

解决递归约束需要一个或多个基本情况;你没有提供任何。问题不在于 Prolog。它与问题定义有关。

【讨论】:

  • 当然,可以将这些相互递归的约束重写为非递归约束,但我的目标是解决相互递归的约束,而无需手动重写它们。 Prolog 有一个SMT solver 可能会使这更容易。
  • 没有任何类型的 no 求解器可以“解决”没有任何基本情况的递归问题。添加基本​​情况不会使其成为非递归的;基本情况是递归定义的一部分
  • 问:“是否有可能在 Prolog 中解决这些约束而不使它们成为非递归的?”;我解释了为什么问题不正确,因此无法解决。
  • @ScottHunter 我再次更新了问题,但添加基本案例并没有完全解决这个问题。
【解决方案2】:

使用constraint handling rules 可以找到相互递归约束的解决方案。

这是一组相互递归的约束:

%If X is an animal, then X is a bird or a mammal, and vice-versa.
:- use_module(library(chr)).

:- chr_constraint mammal/2,bird/2,animal/1,male/1,female/1,species/2.

animal(X) <=> 
    (mammal(X,Species);bird(X,Species)),
    (male(X);female(X)).

male(X),female(X) ==> false.

bird(X,Species) <=> member(Species,[parrot,pigeon,crow]),species(X,Species).
bird(X,Species) ==> animal(X).

mammal(X,Species) <=> member(Species,[cat,dog,bull]),species(X,Species).
mammal(X,Species) ==> animal(X).

species(X,bull) ==> male(X).

...这是该程序查询的输出:

?- male(X),mammal(X,Species).
male(_G67406)
species(_G67406,cat)
Species = cat

【讨论】:

    【解决方案3】:

    我认为你想表达的是你有鸟类和哺乳动物。如果它是鸟类或哺乳动物,您正在进一步尝试确定一个生物是动物。

    目前的代码过度指定,具有循环逻辑。

    浏览代码...

    animal(X) :- 
        (mammal(X); bird(X)).
    

    这表示 Xanimal 如果 XmammalXbird。到目前为止,一切顺利。

    bird的描述如下:

    bird('parrot').
    bird('pigeon').
    

    这些事实表明parrotbirdpigeonbird。但是有这个规则:

    bird(X) :- (X='parrot';X='pigeon'),animal(X).
    

    这表示 Xbird 如果 Xparrotpigeon,如果 Xanimal。前两个事实已经确定parrotpigeon 是鸟类。为什么这个规则是必要的?并且进一步增加了Xanimal的条件,它又是由birdmammal定义的,所以是循环的。

    mammal 定义也是如此。它具有哺乳动物所需的事实:

    mammal('cat').
    mammal('dog').
    

    然后用循环逻辑过度指定

    mammal(X) :- (X='cat';X='dog'), animal(X).
    

    你需要的本质很简单:

    bird('parrot').
    bird('pigeon').
    
    mammal('cat').
    mammal('dog').
    
    animal(X) :- 
        mammal(X); bird(X).
    

    这个逻辑使用事实定义了哪些生物是鸟类或哺乳动物,然后提供了一个规则,即如果一个生物已知是鸟类或哺乳动物,那么它就是动物。

    【讨论】:

    • 此解决方案在这种情况下有效,但我的目标是解决相互递归的约束,而无需以非递归形式手动重写它们。为此,我可能需要使用forward-chaining 推理引擎,例如CHR
    【解决方案4】:

    解决此类问题的一种方法是简单地启用 Prolog 系统的 tableing 机制。

    例如,在 SWI-Prolog(最新开发版本)中,如果我只是在程序开头添加以下指令:

    :- 使用模块(库(表))。
    
    :- 餐桌动物/1。
    

    然后我得到例如:

    ?-动物(X)。 错误的。 ?- 男性(X)。 错误的。 ?- 鸟(X)。 错误的。

    所以,在这些情况下,我们仍然没有找到任何解决方案,但至少我们得到了答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多