2013-07-27 25 views
6

Bardzo nowa w Haskell i próba stworzenia własnej funkcji cofania. Napisałem to tutaj, ale zawsze zwraca pustą listę []:Funkcja odwrotna Haskella

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

może ktoś wyjaśnić, co robię źle?

Dzięki

+5

robi '[długość XS - 1, xs długość - 2..0]' praca? –

+1

Jeśli nie masz jeszcze ochoty na rekursję, przed spojrzeniem na inne implementacje spróbuj zdefiniować 'reverse' w inny sposób, wypełniając następujące:' reverse [] = ...; reverse (x: xs) = ... 'i myśl o tym, że" odwrotnością pustej listy jest ... i odwrotnie do 'x' podanego z listą' xs' jest ... " – jberryman

+3

Pamiętaj, że to ogólnie wątpliwe, aby uzyskać dostęp do list według indeksu. Są one specjalnie zaprojektowane, aby można je było łatwo dekonstruować, z elementu głowicy po elemencie, ale bardzo źle, gdy żądasz elementu w dowolnej pozycji. – leftaroundabout

Odpowiedz

12

Jak groovy wspomniano, są w większości zakresów Haskell przyrostowe - to znaczy, że nie ma pojęcia, jak skonstruować listę malejącą chyba że dasz mu trochę cienia. Zapraszamy do obejrzenia sesji poniżej ghci:

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

Tak, można skonstruować coś takiego:

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

który sprawdza się w ghci tak:

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

spojrzeć pod numerami Unexpected result while reversing a list i How can I write reverse by foldr efficiently in Haskell? w przypadku innych pomysłów dotyczących cofania listy.

+3

Ale nie zapomnij sprawdzić pustą listą i pojedynczą listą. – Ingo

+0

Możesz użyć '' '' wiązania '' foo', aby uniknąć dwukrotnego obliczania długości 'xs'. – Jubobs

5

niejednokrotnie pomaga wymyślić niezmienniki i zapisuje dla nich kilka praw zachowania. Tutaj zauważyć, że

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:[]) 

więc jeśli definiujemy

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

mamy ustawiony. :) To znaczy, dla wywołania rev a b, konkatenacji odwróconej a i b jest zachowany pod transformacji biorąc elementu head z a i poprzedzenie go b, a jest pusty, a potem to tylko b. To może być nawet wyrażana przy użyciu higher-order function until poniższym opisie angielskim, jak

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

Możemy również zdefiniować na przykład teraz revappend funkcja, stosując dokładnie tę samą funkcję wewnętrznej z trochę uszczypnąć, jak my to nazywamy:

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

To moja postać stworzyć własną funkcję odwrotną z rekursji. ta funkcja jest bardzo użyteczna, aby nie definiować funkcji pomocniczych.

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