2013-04-22 62 views
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'的兩個答案。

我認爲這是導致它的最後一行,但我不能在那裏完全停止「!」。或者不能想出任何其他方式來解決這個問題。

什麼需要改變?

回答

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中通常不可能,您將不得不委託給助手。

+0

確實解決了這個問題。謝謝你。花了我一點時間來理解爲什麼getNo(b,[],0)不是一個選項。但是,在比較我的代碼和您的代碼之後,我現在明白了原因。謝謝! – 2013-04-22 22:52:25

+0

@ArturKäpp沒問題。 :)請看我剛剛添加在底部的段落,這可能會說明相同的實現。 – 2013-04-22 22:54:11