第一次结果后功能不会停止 - Prolog

时间:2013-04-22 22:28:09

标签: prolog

我不明白为什么函数在第一次产生后不会停止:

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'的两个答案。

我认为这是造成它的最后一条线,但我不能完全停下来“!”。或者无法想出任何其他解决方法。

需要改变什么?

1 个答案:

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

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

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中通常根本无法完成,您将不得不委托给帮助者。