Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell reverse function

Very new to Haskell, and trying to create my own reverse function. Wrote this here, but it always returns an empty list [] :

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

Can anyone explain what I'm doing wrong?

Thanks

like image 258
caleborp Avatar asked Jul 27 '13 02:07

caleborp


People also ask

How do you reverse a tuple in Haskell?

Wherever you have your code to form the list of tuples, encapsulate that code in a reverse function using brackets (reverse(code)) or reverse $ <code> and the result will be the reverse.

What does drop function do in Haskell?

The "take" function takes an integer and your list and produces the first "n" elements, while "drop" will give you the remainder of the list besides these elements: take :: Int -> [a] -> [a] drop :: Int -> [a] -> [a] Getting the 5 smallest numbers in a list is easy when you combine take and sort .

What is tail Haskell?

The principle of tail recursion is to perform all computation first before the recursive call, often giving the results of the computation as additional argument to the recursively called function. Thus in tail recursion the recursive call is the last logic instruction in the recursive function.

What does Elem mean in Haskell?

Elem Function This function is used to check whether the supplied list contains a specific element or not. Accordingly, it either returns a true or a false. The following code checks whether the supplied list of elements contains the value 786.


2 Answers

As groovy mentioned, Haskell ranges are mostly incremental - that is, it has no idea how to construct a decreasing list unless you give it some hint. Have a look at a ghci session below:

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

So, you can construct something like this:

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

which checks out in ghci like this:

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

Have a look at Unexpected result while reversing a list and How can I write reverse by foldr efficiently in Haskell? for other ideas on reversing a list.

like image 181
S.R.I Avatar answered Nov 09 '22 23:11

S.R.I


oftentimes it helps to invent some invariant and write down some laws of preservation for it. Here notice that

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 if we define

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

we're set. :) I.e., for a call rev a b, the concatenation of reversed a and b is preserved under a transformation of taking a head element from a and prepending it to b, until a is empty and then it's just b. This can even be expressed with the use of higher-order function until following the English description, as

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

We can also define now e.g. an revappend function, using exactly the same internal function with a little tweak to how we call it:

revappend xs ys = rev xs ys  where
  rev (x:xs) acc = rev xs (x:acc)
  rev []     acc = acc
like image 25
Will Ness Avatar answered Nov 10 '22 01:11

Will Ness