你正在帶來很多程序性的想法(「包袱」)來閱讀這個痕跡。讓我們試着用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不能統一keith
與is
,所以它會失敗並進入第二個子句。它不能統一is
與very
,所以它移動到第三子句,並結合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書籍之一,它肯定會詳細介紹這些內容。但我希望這有助於!
在談論內存地址引用和內存中的點時沒有用(這本書是否真的使用這樣的術語?)。 Prolog的操作模型有變量,統一,模式匹配,如果你試圖用這些術語來思考,它可能會更容易。 – 2017-01-03 04:36:56
'alter([very],[very])'succeeded,intended? – false