2009-07-03 73 views
3

我正在學習R5RS Scheme(來自PocketScheme),我發現我可以使用內置於Scheme的某些變體但不是全部的函數:Append!追加!在計劃?

換句話說 - 破壞性地改變列表。

我不是在實際的代碼作爲一個答案這麼多的興趣不亞於理解由哪一個可以傳遞列表作爲一個函數(或載體或字符串),然後變異它的進程。

例如:

(define (append! lst var) 
    (cons (lst var)) 
) 

當我使用的方法如上,我不得不做一些像(define list (append! foo (bar)),我想更多的東西一般。

回答

5

儘管允許突變,但在Scheme中強烈建議不要使用突變。 PLT甚至刪除了set-car!set-cdr!(儘管它們用set-mcar!set-mcdr!「替換」了它們)。但是,append!的規格出現在SRFI-1。這append!是有點不同於你的。在SRFI中,執行可能是,但不是要求修改cons單元以追加列表。

如果你想有一個append!保證要變更被附加到列表中的結構,你可能不得不自己編寫。這並不難:

(define (my-append! a b) 
    (if (null? (cdr a)) 
     (set-cdr! a b) 
     (my-append! (cdr a) b))) 

爲了保持清晰簡單,沒有錯誤檢查在這裏,但很明顯,你將需要在長度至少1爲a清單通過,並(最好)的列表(任何長度)爲ba必須至少爲1的原因是因爲您不能在空列表上登錄set-cdr!

既然你感興趣的是如何工作的,我會看看我能不能解釋一下。基本上,我們想要做的是沿着列表a,直到我們到達最後cons對,這是(<last element> . null)。所以,我們先看看a已經由cdrnull檢查列表中的最後一個元素。如果是,我們使用set-cdr!將其設置爲我們追加的列表,然後我們就完成了。如果不是,我們必須致電my-append!,cdra。每次我們這樣做,我們都會接近a的結尾。由於這是一個變異操作,我們不會返回任何東西,所以我們不需要擔心將修改後的列表形成返回值。

+0

後續問題 - 如果強烈建議忽略突變,那麼對於像「從嚮導對話框構建列表」這樣的模式,最佳做法是什麼? 從Ruby背景來看,這是我一直在努力理解..心態不僅僅是解決問題的實際代碼。 – 2009-07-03 18:15:35

0

比從不爲投入夫婦2-3美分,這個話題猶未晚...

(1)沒有什麼錯誤使用方案破壞性程序,同時有一個單一的參考結構被修改。因此,例如,有效地建立大的列表中,通過單個參考零碎 - 和完成時,使公知的,並從不同的對象,稱爲該(現在大概不要被改性的)列表。

(2)我想追加!應該像APPEND一樣行事,只有(可能)具有破壞性。所以APPEND!應該期待任何數量的列表作爲參數。每個列表,但最後大概是SET-CDR!'d到下一個。

(3)上面的APPEND!基本上來自Mac Lisp和Common Lisp的NCONC。 (和其他lisps)。