2017-01-03 55 views
1

從Clocksin,Mellish編寫的Prolog(2003)中編寫時出現了問題。Prolog:在實現目標時的變量實例

假設我們用列表來從一個句子映射到另一個

change(keith, he). 
change(very, too). 
change(X, X). 

alter([], []). 
alter([H|T], [X|Y]) :- change(H, X), alter(T, Y). 

可能有人闡明變量是如何被實例化?我的書沒有特別深入這一點。

例如,使用跟蹤時:

Call: (7) alter([keith, is, very, cool], _G2676) ? creep 
Call: (8) change(keith, _G2756) ? creep 
Exit: (8) change(keith, he) ? creep 
Call: (8) alter([is, very, cool], _G2757) ? creep 
Call: (9) change(is, _G2759) ? creep 
Exit: (9) change(is, is) ? creep 
Call: (9) alter([very, cool], _G2760) ? creep 
Call: (10) change(very, _G2762) ? creep 
Exit: (10) change(very, too) ? creep 
Call: (10) alter([cool], _G2763) ? creep 
Call: (11) change(cool, _G2765) ? creep 
Exit: (11) change(cool, cool) ? creep 
Call: (11) alter([], _G2766) ? creep 
Exit: (11) alter([], []) ? creep 
Exit: (10) alter([cool], [cool]) ? creep 
Exit: (9) alter([very, cool], [too, cool]) ? creep 
Exit: (8) alter([is, very, cool], [is, too, cool]) ? creep 
Exit: (7) alter([keith, is, very, cool], [he, is, too, cool]) ? creep 
B = [he, is, too, cool] . 

我看到幾個內存地址的引用在規則中遇到ALTER時開放,爲和遞歸配對爲:

alter([is, very, cool], ???? tail of Z 

它似乎新的Y會取Z的尾部值,但由於Z只是對內存中某個點的引用,這些變量在返回之前如何賦值?同樣來自這種混淆的是,我無法闡明在alter謂詞中尾部X的值如何能夠「建立起來」,因爲它在那裏保留了來自變化謂詞的新值。

+2

在談論內存地址引用和內存中的點時沒有用(這本書是否真的使用這樣的術語?)。 Prolog的操作模型有變量,統一,模式匹配,如果你試圖用這些術語來思考,它可能會更容易。 – 2017-01-03 04:36:56

+1

'alter([very],[very])'succeeded,intended? – false

回答

2

你正在帶來很多程序性的想法(「包袱」)來閱讀這個痕跡。讓我們試着用Prolog的眼睛閱讀它:

Call: (7) alter([keith, is, very, cool], _G2676) ? creep 

Prolog只是在這裏重申你的目標。您可以忽略生成的變量_G2676中的數字;它不是一個內存位置,生成這些變量名稱的方法因實現和平臺而異,在Prolog中沒有任何機制可以讀取任意內存位置,而且這些生成的變量編號在幾乎任何意義上都是無法訪問的。這只是一個內部簿記的事情。

你可能發出這樣的詢問:

?- alter([keith, is, very, cool], B). 

想想看這樣的。你在問Prolog,「證明alter([keith, is, very, cool], B)並告訴我B是什麼。」所以它會嘗試去做。

Call: (8) change(keith, _G2756) ? creep 

這裏發生了什麼事? Prolog查看了您的查詢,並看到您正在使用alter/2。它用alter/2代替主體主體alter/2。快速Prolog的解剖課:

alter([H|T], [X|Y]) :- change(H, X), alter(T, Y). 
------------------- -------------------------- 
    "the head"     "the body" 

所以序言說,「來證明alter([keith,is,very,cool], B)我必須證明alter([H|T], [X|Y])[keith,is,very,cool] = [H|T]B = [X|Y](Prolog的管理在合理的方式將這些變量名。)所以現在序言取代。 。與change(H, X), alter(T, Y)活動查詢除外,[H|T] = [keith|[is,very,cool]]B = [X|Y]那麼得到的跟蹤印刷是:

Call: (8) change(keith, _G2756) ? creep 

現在Prolog必須查看它的第一個子句change/2,它發現change(keith, he)。所以Prolog說:「啊哈!X = he「然後打印:

Exit: (8) change(keith, he) ? creep 

序言現在說,」 OK,我只需要完成該查詢我開始了第二次前通過查看的alter/2的身體,這是下一步:

Call: (8) alter([is, very, cool], _G2757) ? creep 

嗯,就像以前一樣,序言現在正與alter/2的機構,以取代alter/2查詢並努力實現它,這意味着它現在必須證明:

Call: (9) change(is, _G2759) ? creep 

這一個稍微有趣,因爲change/2的第一個子句不匹配。 Prolog不能統一keithis,所以它會失敗並進入第二個子句。它不能統一isvery,所以它移動到第三子句,並結合is與自身:

Exit: (9) change(is, is) ? creep 

重複此過程,遞給非常/太和/酷,然後Prolog的運行列表中進行成分和輸入您的基本案例alter/2

Call: (11) alter([], _G2766) ? creep 
Exit: (11) alter([], []) ? creep 

如果你關注,你應該注意到,與匿名變量查詢行開始Call:,以表明Prolog是改變的問題,並在序言回答問題,該行以開頭。還有一些其他的東西可以開始,告訴你關於Prolog的執行模型的其他信息:Retry:Fail:。但是你沒有在這裏,因爲你的查詢實際上是第一次嘗試。

從這裏開始,你只需要得到Exit,因爲一切都已經成功地統一了,Prolog基本完成了。但是,這是在「建設」正在發生的事情:

Exit: (11) alter([], []) ? creep 
Exit: (10) alter([cool], [cool]) ? creep 
Exit: (9) alter([very, cool], [too, cool]) ? creep 
Exit: (8) alter([is, very, cool], [is, too, cool]) ? creep 
Exit: (7) alter([keith, is, very, cool], [he, is, too, cool]) ? creep 

這裏發生的事情是,alter([], [])被證實,所以它返回到外來電(注意數字的存在,他們告訴你關於調用堆棧) ,這意味着Prolog現在已經證明alter([cool], [cool])是正確的,這意味着已經證明alter([very, cool], [too, cool])是真實的,等等。這只是人們期望的尾部遞歸。最後,輸出到您的查詢成功:

B = [he, is, too, cool] . 

所以,真的沒有內存地址被打開,在這裏,因爲你把它。

看來新的Y會取Z的尾部值,但由於Z只是對內存中某個點的引用,這些變量在返回之前如何賦值?

在「正常」編程語言中,您可以使用某些值調用某個函數,並且您將返回一個值作爲返回值。 Prolog不是一種正常的編程語言;你沒有定義函數,你正在定義關係。一個關係比一個函數的約束更少:有時你的參數是輸入,有時它們是輸出。 Prolog中的變量不是「引用內存中的點」。它們只是數據的名稱;他們可以是地面免費取決於他們是否已經計算出來。

在Prolog,Prolog中的每一步評估都在尋找自由變量的綁定。這被稱爲統一並且是Prolog中的基本執行模型。當您發出像change(keith, X)這樣的查詢時,您正在要求Prolog證明change(keith, X)爲真,併爲您提供使其成立的值X. Prolog會查看並返回true, X = he。但你也可以問它change(X, he)和Prolog會看它,並說,true, X = keith。這是使它成爲關係而不是功能的一部分。你也可以說change(X, Y),它會回來與true, X = keith & Y = he; X = very & Y = too; X = Y和結果的多樣性是另一種方式,你知道你正在處理關係,而不是功能。

因此,在Prolog中,變量不是「內存中的點」,它是名稱和值之間的綁定,Prolog能夠在評估中的任何一步建立綁定,而不僅僅是在或者在計算過程中,但也是在成功計算的過程中!

我敢打賭,如果你回頭看你的書,你會發現它有很多關於這方面的細節。它是那裏最好的Prolog書籍之一,它肯定會詳細介紹這些內容。但我希望這有助於!

+0

謝謝丹尼爾。看起來我並不認爲「外部」呼叫仍然是「打開」的 - 這足以說明遞歸的整個概念!我會重讀本書的開頭。 – Krpcannon