2013-07-27 21 views
6

Sehr neu zu Haskell, und versuche, meine eigene Umkehrfunktion zu erstellen. Schrieb dies hier, aber es gibt immer eine leere Liste []:Haskell Reverse-Funktion

reverse' :: [a] -> [a] 
reverse' xs = [xs !! k | k <- [((length xs) - 1)..0]] 

Kann jemand erklären, was ich falsch mache?

Dank

+5

tut '[Länge xs - 1, Länge xs - 2..0]' Arbeit? –

+1

Wenn Sie sich mit der Rekursion noch nicht auskennen, sollten Sie, bevor Sie sich andere Implementierungen ansehen, versuchen, 'reverse' anders zu definieren, indem Sie Folgendes eingeben:' reverse [] = ...; reverse (x: xs) = ... 'und denke an es als" die Umkehrung der leeren Liste ist ... und die Umkehrung von 'x' in Übereinstimmung mit der Liste' xs' ist ... " – jberryman

+3

Beachten Sie, dass es ist im Allgemeinen fraglich, um Listen nach Index zugreifen zu können. Sie sind speziell so konzipiert, dass Sie sie leicht rekursiv vom Kopf Element für Element dekonstruieren können, aber sehr schlecht funktionieren, wenn Sie ein Element an einer beliebigen Position anfordern. – leftaroundabout

Antwort

12

Wie groovy erwähnt, sind Haskell Bereiche meist inkrementalen - das heißt, es hat keine Ahnung, wie man eine absteigende Liste zu konstruieren, wenn Sie es einen Hinweis geben. Werfen Sie einen Blick auf eine GHCI Sitzung unter:

Prelude> [5..0] 
[] 
Prelude> [5,4..0] 
[5,4,3,2,1,0] 

Also, Sie so etwas wie dieses Konstrukt kann:

foo xs = [(length xs-1), (length xs -2)..0] 
rev xs = [xs !! k| k <- foo xs] 

, die wie folgt in GHCI auscheckt:

Prelude> rev [1..5] 
[5,4,3,2,1] 

Werfen Sie einen Blick bei Unexpected result while reversing a list und How can I write reverse by foldr efficiently in Haskell? für andere Ideen zum Umkehren einer Liste.

+3

Aber vergessen Sie nicht, mit einer leeren Liste und Singleton-Liste zu überprüfen – Ingo

+0

Sie könnten eine 'where' Bindung in' foo' verwenden, um zu vermeiden, die Länge von 'xs' zweimal zu berechnen. – Jubobs

5

oft hilft es, einige Invarianten zu erfinden und einige Erhaltungsgesetze dafür aufzuschreiben. Hier bemerken, dass

reverse xs  = reverse xs ++ [] 
reverse (x:xs) = (reverse xs ++ [x]) ++ [] 
       = reverse xs ++ ([x] ++ []) 
       = reverse xs ++ (x:[]) 
reverse (x:(y:xs)) = 
       = reverse (y:xs) ++ (x:[]) 
       = reverse xs ++ (y:x:[]) 
...... 
reverse (x:(y:...:(z:[])...)) = 
       = reverse [] ++ (z:...:y:x:[]) 

so, wenn wir

reverse xs = rev xs [] where 
    rev (x:xs) acc = rev xs (x:acc) 
    rev []  acc = acc 

definieren wir gesetzt sind. :) Das heißt, für einen Anruf rev a b, die Verkettung von umgekehrt a und b unter einer Transformation erhalten ein Kopfelement aus a des Nehmens und vorangestellt, es zu b, bisa leer ist und dann b es ist einfach. Dies kann auch bei der Verwendung von higher-order function until nach der englischen Beschreibung ausgedrückt werden, als

{-# LANGUAGE TupleSections #-} 
reverse = snd . until (null.fst) (\(a,b)-> (tail a,head a:b)) . (, []) 

Wir definieren nun auch z eine revappend Funktion, mit genau die gleichen internen Funktion mit einem kleinen Kniffe, wie wir es nennen:

revappend xs ys = rev xs ys where 
    rev (x:xs) acc = rev xs (x:acc) 
    rev []  acc = acc 
0

Das ist meine Form ist meine eigene Reverse-Funktion mit Rekursion zu erstellen. Diese Funktion ist sehr nützlich, um Hilfsfunktionen nicht zu definieren.

list = [] reverse [x] = list ++ [x] reverse = list ++ [last l] ++ reverse (init l)