0

我不明白为什么函数在第一次导致这个之后没有停止:

getNo(A, [[A,X]|_], X).
getNo(A, [_|Tail], X):- 
    getNo(A, Tail, X), !.
getNo(_,[],0).

示例输入:

?- getNo(a,[[a,2],[b,1]],X).
X = 2 ;
X = 0.

?- getNo(b,[[a,2],[b,1]],X).
X = 1.

?- getNo(c,[[a,2],[b,1]],X).
X = 0.

当元素不是数组中的第一个元素时,句号有效。但是为什么它不停止数组中的第一个元素。为什么它在示例输入中为“a”提供两个答案。

我认为这是导致它的最后一行,但我不能在那里句号“!”。或者无法想出任何其他方法来解决这个问题。

需要改变什么?

4

1 回答 1

2

为清楚起见,感叹号是剪切运算符,它不表现为“句号”。它只是将您提交给在运行之前所做的选择。通过跟踪我们可以看到它实际上与您遇到的问题无关:

?- getNo(a,[[a,2],[b,1]],X).
X = 2 ; [trace]
   Redo: (6) getNo(a, [[a, 2], [b, 1]], _G221) ? creep
   Call: (7) getNo(a, [[b, 1]], _G221) ? creep
   Call: (8) getNo(a, [], _G221) ? creep
   Exit: (8) getNo(a, [], 0) ? creep
   Exit: (7) getNo(a, [[b, 1]], 0) ? creep
   Exit: (6) getNo(a, [[a, 2], [b, 1]], 0) ? creep
X = 0.

所以你可以在这里看到getNo(a, [], 0)它也会成功。它也可以自己做,因为没有什么可以阻止它:

?- getNo(a,[],X).
X = 0.

没有理由期望它可以通过递归调用或仅通过使用 cut 的直接调用来区分到达空列表的情况。我认为你必须重组你的谓词以获得你想要的行为。例如:

get_number(A, [[A,X]|_], X).
get_number(A, [_|Tail],  X)  :- get_number(A, Tail, X).

getNo(A, L, X) :- get_number(A, L, X), !.
getNo(_, _, 0).

作为关于使用 Prolog 的附加说明,您经常需要创建另一个谓词。不要害怕创建辅助谓词。除此之外,没有其他方法可以真正处理需要设置初始条件或后处理的循环。在其他语言中,您可以将需要做的所有工作完全隔离在单个函数的接口后面,但在 Prolog 中,这通常是不可能的,您必须委托给助手。

于 2013-04-22T22:47:24.867 回答