0

我正在创建一个应该允许通过图形搜索的程序,但是当对 findall/3 的调用评估为 false 时,应该返回后继节点列表的函数失败。当我在 find_successors 函数之外单独尝试 findall 函数时,它运行良好,但由于某种原因在 find_successors 函数内部,它只是读取为 false。逐步使用图形调试器,我什至可以看到它找到了所有解决方案。这是代码:

find_successors(Start, Out) :- 
    entity(Start),
    (findall(X, is_a(Start, X), O), append([], O, OL1); OL1 = []),
    (findall(X, is_a(X, Start), O), OL2 = O; OL2 = []),

    (findall(X, has(Start, X), O), append([], O, OL3); OL3 = []),
    (findall(X, has(X, Start), O), append([], O, OL4); OL4 = []),

    (findall(X, able_to(Start, X), O), append([], O, OL5); OL5 =[]),
    (findall(X, able_to(X, Start), O), append([], O, OL6); OL6 = []),

    (findall(X, used_to(Start, X), O), append([], O, OL7); OL7 = []),
    (findall(X, used_to(X, Start), O), append([], O, OL8); OL8 = []),

    append([OL1, OL2, OL3, OL4, OL5, OL6, OL7, OL8], Out).

entity(wings).
entity(fly).
entity(bird).
entity(legs).
entity(feathers).
entity('body covering').
entity(animal).
entity(dog).
entity(fur).
entity(aves).
entity(reptile).
entity(snake).
entity(scales).

f_is_a(bird, aves).
f_is_a(bird, animal).
f_is_a(snake, reptile).
f_is_a(snake, animal).
f_is_a(dog, mammal).
f_is_a(dog, animal).
f_is_a(feathers, 'body covering').
f_is_a(fur, 'body covering').
f_is_a(mammal, animal).
f_is_a(reptile, animal).
f_is_a(aves, animal).
is_a(X, H) :- !, f_is_a(X, H).
is_a(X, H) :- !, \+f_is_a(X, P), H = X.
is_a(X, H) :- !, is_a(X, P), is_a(P, H).

f_has(bird, wings).
f_has(bird, feathers).
f_has(bird, legs).
f_has(aves, wings).
f_has(aves, feathers).
f_has(aves, legs).
f_has(dog, legs).
f_has(dog, fur).
f_has(mammal, legs).
f_has(mammal, fur).
f_has(snake, scales).
f_has(reptile, scales).
has(X, H) :- !, f_has(X, H).
has(X, H) :- !, \+f_has(X, P), H = X.
has(X, H) :- !, has(X, P), has(P, H).

used_to(wings, fly).
used_to(legs, walk).

able_to(bird, fly).
able_to(bird, walk).
able_to(dog, walk).
able_to(X, Y) :- used_to(X1, Y), has(X, X1).
4

2 回答 2

2

你不断尝试重用同一个变量,但是一旦绑定了一个变量,你就不能再使用它了。所以所有这些:

        here              here
         |                  |
         v                  v
(findall(X, is_a(Start, X), O), append([], O, OL1); OL1 = []),
(findall(X, is_a(X, Start), O), OL2 = O; OL2 = []),

(findall(X, has(Start, X), O), append([], O, OL3); OL3 = []),
(findall(X, has(X, Start), O), append([], O, OL4); OL4 = []),

(findall(X, able_to(Start, X), O), append([], O, OL5); OL5 =[]),
(findall(X, able_to(X, Start), O), append([], O, OL6); OL6 = []),

(findall(X, used_to(Start, X), O), append([], O, OL7); OL7 = []),
(findall(X, used_to(X, Start), O), append([], O, OL8); OL8 = []),

每一行都非常非常奇怪。我需要分解它才能真正弄清楚发生了什么。只取其中之一:

(   findall(X, used_to(Start, X), O),
    append([], O, OL7)
;   OL7 = []
)

(顺便说一句,这就是你应该如何尝试写析取,否则它们很容易被误读)

append([], A, B)是一样的A = B

然后,findall/3总是成功,即使没有解决方案;它只是给你一个空列表!

?- findall(X, between(2, 1, X), Xs).
Xs = [].

所以整个事情是完全没有必要的,你可以扔掉除了调用之外的所有东西findall/3

请注意:您使用的析取并不像您认为的那样。这是一个小例子:

?- ( A = 1 ; A = 2 ).

你认为会发生什么?

于 2016-11-30T21:11:34.483 回答
0

您应该建议我们打电话给我们find_successors(Start, Out)并说出预期值。

没有它很难说你的代码哪里错了,但是......没有特定顺序的一些点......

(1)append/3连接将第三个参数与连接第一个和第二个列表中的元素获得的列表统一起来;所以

append([], O, OL1)

第一个参数中没有元素,unify Owith OL1so 是没有用的;您可以在表格中写下所有行

(findall(X, is_a(Start, X), O), append([], O, OL1); OL1 = []),

作为

(findall(X, is_a(Start, X), OL1) ; OL1 = []),

(2)findall/3将第三个参数与空列表统一时也返回 true(当没有找到值时),所以我不明白你为什么要写

(findall(X, is_a(Start, X), OL1) ; OL1 = []),

当第二部分 ( OL1 = []) 从未执行时(如果我没记错的话),何时OL1[]何时findall/3无所事事统一;我想你可以简单地写

findall(X, is_a(Start, X), OL1),

(3) 我只知道一个append带有三个参数的;所以我不明白

append([OL1, OL2, OL3, OL4, OL5, OL6, OL7, OL8], Out)

你的意图是写

append([], [OL1, OL2, OL3, OL4, OL5, OL6, OL7, OL8], Out)

?

在这种情况下,考虑到计数 (1) 和 (2),您可以find_successors/2简单地写为

find_successors(Start, [OL1, OL2, OL3, OL4, OL5, OL6, OL7, OL8]) :- 
    entity(Start),
    findall(X, is_a(Start, X), OL1),
    findall(X, is_a(X, Start), OL2),
    findall(X, has(Start, X), OL3),
    findall(X, has(X, Start), OL4),
    findall(X, able_to(Start, X), OL5),
    findall(X, able_to(X, Start), OL6),
    findall(X, used_to(Start, X), OL7),
    findall(X, used_to(X, Start), OL8).

(4)我不喜欢削减(!)所以也许我错了但是......你为什么把!作为第一个元素放在is_a/2

is_a(X, H) :- !, f_is_a(X, H).
is_a(X, H) :- !, \+f_is_a(X, P), H = X.
is_a(X, H) :- !, is_a(X, P), is_a(P, H).

如果我没记错的话,第一个子句 ( !, f_is_a(X, H)) 中的剪切会禁用第二个和第三个子句,因此,如果f_is_a(X, H)失败,则永远不会验证第二个和第三个子句。

你确定你的意图不是

is_a(X, H) :- f_is_a(X, H), !.
is_a(X, H) :- \+f_is_a(X, P), H = X, !.
is_a(X, H) :- is_a(X, P), is_a(P, H), !.

或更好

is_a(X, H) :- f_is_a(X, H), !.
is_a(X, X) :- \+f_is_a(X, _), !.
is_a(X, H) :- is_a(X, P), is_a(P, H), !.

?

还是根本不剪?

(5) 相同的切割问题has/3;我怀疑

has(X, H) :- !, f_has(X, H).
has(X, H) :- !, \+f_has(X, P), H = X.
has(X, H) :- !, has(X, P), has(P, H).

是错误的,你的意图是

has(X, H) :- f_has(X, H), !.
has(X, H) :- \+f_has(X, P), H = X, !.
has(X, H) :- has(X, P), has(P, H), !.

或更好

has(X, H) :- f_has(X, H), !.
has(X, X) :- \+f_has(X, _), !.
has(X, H) :- has(X, P), has(P, H), !.

还是根本不剪?

于 2016-11-30T21:15:08.190 回答