findall / 3错误地评估为false

时间:2016-11-30 19:46:46

标签: prolog prolog-findall

我正在创建一个允许通过图形搜索的程序,但是当对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).

2 个答案:

答案 0 :(得分: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 ).

您认为会发生什么?

答案 1 :(得分:0)

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

如果没有它,很难说你的代码在哪里出错了......但某些点没有特别的顺序......

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

append([], O, OL1)

第一个参数中没有元素,将OOL1统一起来,因此无用;你可以写表格中的所有行

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

as

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

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

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

当第二部分(OL1 = [])从未执行时(如果我没有错),当OL1[]找不到任何内容时findall/3findall(X, is_a(Start, X), OL1), 统一时;我想你可以简单地写一下

append

(3)我只知道有append([OL1, OL2, OL3, OL4, OL5, OL6, OL7, OL8], Out) 个三个论点;所以我不明白

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

你打算写

find_successors/2

在这种情况下,考虑到计数(1)和(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))中的cut会禁用第二个和第三个子句,因此,如果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), !. 失败,则永远不会验证第二个和第三个子句。< / p>

你确定你的意图不是

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), !.

或更好

has/3

还是根本不切?

(5)与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), !.

或更好

public class Lunch implements Parcelable {

private String mName;
private float priceStud;
private float priceEmp;
private float priceGuest;
private ArrayList<Lunch> m = new ArrayList<Lunch>();
public static final int PRICE_STUDENT = 0;
public static final int PRICE_EMPLOYEE = 1;
public static int PRICE_GUEST = 2;

public Lunch(Parcel in) {
    setmName(in.readString());
    setPriceStud(in.readFloat());
    setPriceEmp(in.readFloat());
    setPriceGuest(in.readFloat());
}
@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(getmName());
    dest.writeFloat(getPriceGuest());
    dest.writeFloat(getPriceEmp());
    dest.writeFloat(getPriceStud());
}

public static final Creator<Lunch> CREATOR = new Creator<Lunch>() {
    public Lunch createFromParcel(Parcel in) {
        return new Lunch(in);
    }

    public Lunch[] newArray(int size) {
        return new Lunch[size];
    }
};

还是根本不切?