Reputation: 9649
Tried to mimic the reverse
function to the ADT List
below,
data List a = Nil | Cons a (List a) deriving (Show)
reverseList = convert . reverse'
where
reverse' Nil = []
reverse' (Cons x list) = reverse' list ++ [x]
convert [] = Nil
convert (x:xs) = Cons x (convert xs)
The reverseList
is composed of convert
and reverse'
, how to achieve it optimally for instance without the aid of the built-in list?
Upvotes: 1
Views: 220
Reputation: 116139
In my view, the most basic O(N) solution is to use recursion and an accumulator:
revlist :: List a -> List a
revlist xs = go xs Nil
where
go :: List a -> List a -> List a
go Nil zs = zs
go (Cons y ys) zs = go ys (Cons y zs)
This exploits go
, a tail-recursive function which essentially uses the two lists as stacks, repeatedly popping elements form the first stack and pushing them to the second stack. Once the first stack is empty, the second stack contains the reversed list.
Upvotes: 2
Reputation: 3645
Starting from this answer to a similar question, you can let the compiler derive a Traversable
instance to your List
type:
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
data List a = Nil | Cons a (List a) deriving (Show, Functor, Foldable, Traversable)
--You need the Functor and Foldable instances
Then, reverse'
becomes simply:
reverse' = foldl (flip Cons) Nil
which is O(N) time complexity.
Upvotes: 2
Reputation: 26161
You may perhaps do it in an applicative style efficiently. It should be O(n)
data List a = Nil | Cons a (List a) deriving Show
conc :: List a -> List a -> List a
conc Nil xs = xs
conc (Cons x xs) ys = Cons x $ conc xs ys
revlist :: List a -> List a
revlist xs = go xs Nil -- invoke go xs function by Nil
where
go :: List a -> (List a -> List a)
go Nil = conc Nil -- such as ([]++)
go (Cons x xs) = go xs . conc (Cons x Nil) -- such as go xs . ([x]++)
λ> revlist (Cons 1 (Cons 2 (Cons 3 Nil)))
Cons 3 (Cons 2 (Cons 1 Nil))
We are nesting the concatenation operations (conc
) to the right. This is basically difference lists.
Upvotes: 1
Reputation: 18249
All you need to do is translate all the list functions you're using to ones on your List
type. Here this means ++
- let's define this for your version, and call it say listConcat
(feel free to come up with your own name):
listConcat :: List a -> List a -> List a
listConcat Nil as = as
listConcat (Cons a as) bs = Cons a (listConcat as bs)
And then you can just translate the definition of reverseList
that you already have:
reverseList :: List a -> List a
reverseList Nil = Nil
reverseList (Cons a as) = listConcat (reverseList as) (Cons a Nil)
Upvotes: 1