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
[length xs - 1, length xs - 2..0]work?reverseanother way by filling in the following:reverse [] = ... ; reverse (x:xs) = ...and think of it as "the reverse of the empty list is ... and the reverse ofxconsed with the listxsis ..."