2010-07-03 167 views
7

下面是我的代碼,它將列表(carVal)的汽車元素和列表(初始化爲空)作爲參數。我想將元素追加到列表中,但同樣不起作用。在方案中添加元素列表

(define populateValues 
    (lambda (carVal currVal) 
     (append currVal(list carVal)) 
     (display currVal))) 

顯示屏始終顯示空列表()。任何人都可以幫我理解爲什麼?

回答

21

嗯,有append!作爲一種原始的,它解決了大部分的問題,如前所述,方案往往皺眉在突變時,這是可能的,但通常可以避免,因此所有突變的程序在其末尾都有一個!(稱爲爆炸)。

另外,set!不改變數據,它改變了環境,它使得一個變量指向另一個東西,原始數據保持不變。

Scheme中的突變數據非常麻煩,但是,爲了讓我自己實現append!看看它是如何做:

(define (append! lst . lsts) 
    (if (not (null? lsts)) 
     (if (null? (cdr lst)) 
      (begin 
      (set-cdr! lst (car lsts)) 
      (apply append! (car lsts) (cdr lsts))) 

      (apply append! (cdr lst) lsts)))) 

注意使用set-cdr!,這是一個真正的突變,它僅適用於對,它在內存中的數據發生突變,不像'設置「!。如果一對被傳遞給一個函數並且使用set-cdr進行了變異!或set-car!,它會在程序中的每一處發生變異。

這服從SRFI追加!規範說,它應該是可變的,它應該返回一個未定義的值,例如。

(define l1 (list 1 2 3 4)) 

(define l2 (list 2 3 4)) 

(define l3 (list 3 1)) 

(append! l1 l2 l3) 

l1 

l2 

l3 

該款顯示器:

(1 2 3 4 2 3 4 3 1) 
(2 3 4 3 1) 
(3 1) 

中可見,追加!可以採取無數的論點,它會改變他們,但最後。

雖然計劃可能不是您理想的語言。使用追加!如前所述是非標準的,相反,append是首選的,它不會變異並被調用它的返回值。這是我實現這樣:

(define (append . lsts) 
    (cond 
    ((null? lsts) '()) 
    ((null? (car lsts)) (apply append (cdr lsts))) 
    (else (cons (caar lsts) (apply append (cdar lsts) (cdr lsts)))))) 


> (append (list 1 2 3) (list 4 5 6) (list 'granny 'porn)) 
(1 2 3 4 5 6 granny porn) 

這都說明在沒有突變,大量使用遞歸 的和沒有用測序更熟悉方案的風格。

編輯:如果你只是想一些元素添加到列表中,而不是本身連接兩個雖然:

(define (extend l . xs) 
    (if (null? l) 
     xs 
     (cons (car l) (apply extend (cdr l) xs)))) 

(define (extend! l . xs) 
    (if (null? (cdr l)) 
     (set-cdr! l xs) 
     (apply extend! (cdr l) xs))) 

(extend '(0 1 2 3) 4 5 6) 

(define list1 '(0 1 2 3)) 

(extend! list1 4 5 6) 

list1 

哪個做你所期望的

+0

謝謝你的答案..順便說一句......'奶奶','色情'..你可能想改變他們..否則你可能會被投票:) – 2010-07-16 04:40:49

+0

@ darkie15它不會使答案不那麼'有用'或'明確',如果人們因爲這些事情想要降低它的話,那麼這個網站已經失去了。此外,無論如何,你已經得到了答案。 =) 此外,其他人可以編輯它,如果他們想。 – Zorf 2010-07-16 19:18:09

2

(append foo bar)返回級聯foobar。它不會更改foobar

0

您必須用set!更新currVal的值。你的榜樣應該有

(set! currVal (append currVal (list carVal)) 
(display currVal) 
+0

請注意,這將改變函數內的'currVal',但在外面沒有可見的效果。 – 2010-07-03 21:13:27

5
  1. append創建一個新名單,它不修改現有的一個。
  2. 這是因爲一般情況下,方案(和本例中的球拍)是一種喜歡功能風格的語言。
  3. 你可能會更接近set! - 但即使這樣也會讓你失望,因爲它只會修改本地綁定。
  4. 請注意,在球拍特別是,列表是不可變的,所以有沒有可以改變列表。
  5. 此外,即使您可以用這種方式修改列表,但由於您必須重複掃描整個列表,因此累積長列表是非常低效的方式。
  6. 最後,如果你在這個級別有問題,那麼我強烈建議去在HtDP
+0

我需要拿出這個功能。你會在這種情況下建議什麼? – 2010-07-03 20:54:30

+0

你可以使用'box',這是一種指向(可變)值的指針。 **但是**我懷疑你確實需要這個功能 - 新手們通常認爲他們必須這樣做,因爲他們習慣於突變是做事情的唯一方式。 – 2010-07-03 20:58:11

0

你真的需要想想什麼確切的功能你正在尋找

如果你想改變引用列表的地方,那麼你必須做相當於追加! (如其他答案中所述)。但是這很危險,因爲你可能有其他的代碼是不可改變的,如果你打算這麼做的話,你的程序需要有一個!最終標誌着這種危險。

一個廉價的逼近,你想要做什麼,更實用的風格,就是:

(define (populateValues carVal currVal) 
(let ((ll (append currVal (list carVal)))) 
    (display ll) 
    ll)) 

注意,它使一個新的列表,不追加,顯示結果,並返回新名單作爲一種價值。如果您無法訪問中間值,則這是一種有用的調試技術:綁定到變量,顯示或記錄它,然後返回它。