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? – גלעד ברקןreverse
another 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 ofx
consed with the listxs
is ..." – jberryman