2014-09-01 54 views
3

我有一個函數來扭轉在列表中的元素的順序,如如何扭轉列表元素的順序方案

(define (rvsl sequence) 
    (foldl (lambda (x y) 
      (cons y x)) 
     '() sequence)) 

然而,當我跑了它在DrRacket與輸入

(rvsl (list 2 3 4)) 

DrRacket告訴我這

cons: second argument must be a list, but received empty and 2 

有誰請給我一些想法去解決呢?

在此先感謝!

+1

只需使用'(cons x y)'而不是'(cons y x)'。 – 2014-09-01 14:15:30

+0

您定義了rvsl以獲取兩個參數,並且只有在您使用它時才傳遞它。您可以從一開始就傳遞兩個參數,或者創建另一個將正確數量的參數傳遞給rvsl的過程。 – malisper 2014-09-01 15:38:56

回答

2

您的代碼的問題在於您傳遞的參數順序錯誤 - 使用cons構建列表時,第一個參數是我們要在列表開始處粘貼的新元素,而第二個是我們迄今爲止建立的名單。

話雖如此,扭轉使用foldl名單是有點簡單,你不需要使用append在所有 - 事實上,它是一個使用append一種不好的做法時cons足夠:

(define (rvsl sequence) 
    (foldl cons 
     '() 
     sequence)) 

爲什麼這有用嗎?讓我們重寫功能更加明確的這段時間:

(define (rvsl sequence) 
    (foldl (lambda (current accumulated) 
      (cons current accumulated)) 
     '() 
     sequence)) 

現在我們可以看到,lambda過程接收兩個參數:輸入列表中的current元素,以及accumulated值爲止 - 好參數名讓所有的世界上的差異!這比調用參數xy要清楚得多,它沒有提到它們。

在這種情況下,我們只需要cons當前元素在累積值的頭部(它以空列表開頭),因此產生一個反轉列表作爲輸出。鑑於lambda過程接收到兩個參數並將它們以相同順序傳遞到cons,我們可以簡化整個過程,並將cons過程作爲參數傳遞。

0

你不要使用foldl或其他任何東西,實際上,定義rev函數; rev函數本身就足夠了:

(define (rev ls)         ; rev [] = [] 
    (cond           ; rev [x] = [x] 
    ((null? ls) ls)        ; rev (x:xs) 
    ((null? (rest ls)) ls)      ; | (a:b) <- rev xs 
    (else          ; = a : rev (x : rev b) 
     (cons (first (rev (rest ls))) 
      (rev (cons (first ls) 
         (rev (rest (rev (rest ls)))))))))) 

(在等式模式匹配僞代碼中的註釋)。推導和一些討論here

編輯:這顯然是一個玩具代碼,只是爲了磨練你的Scheme-fu)。

1

這是一個簡單的版本,使用內部迭代過程。

(define (rev lst) 
    (define (iter accum lst) 
    (if (null? lst) 
     accum 
     (iter (cons (car lst) accum) 
       (cdr lst)))) 
    (iter '() lst))