Reputation: 755
Is there an easier way (maybe a standard function) to do this:
(If the list contains the element, the result is the next element of the list; if the element is the last element of the list, the result is the first element of the list. "Special cases": If the list is empty, the result is Nothing. If the list doesn't contain the element, the result is the first element of the list.)
import Data.List
next :: Eq a => Maybe a -> [a] -> Maybe a
next _ [] = Nothing
next Nothing (x:_) = Just x
next (Just x) list = Just $ list !! index
where index =
case elemIndex x list of
Nothing -> 0
Just xIndex ->
if xIndex + 1 == length list
then 0
else xIndex + 1
Upvotes: 0
Views: 5908
Reputation: 15605
By zipping a list with its tail, we obtain an association list of elements and their successors:
> lookup 1 $ (zip <*> tail) [1,2,3,4]
Just 2
> lookup 4 $ (zip <*> tail) [1,2,3,4]
Nothing
It is also lazy:
> lookup 4 $ (zip <*> tail) [1..]
Just 5
Upvotes: 2
Reputation: 2944
First I'd change the signature of your function, usually you don't define functions that apply only on Maybe.
So I introduce a function that returns the part of the list after the given element.
following :: (Eq a) => a -> [a] -> [a]
following _ [] = []
following x (y:l) = if x==y then l else following x l
Then I define next that returns the first element of 'following x l' or the first element of the list.
next :: (Eq a) => [a] -> a -> Maybe a
next [] _ = Nothing
next l x = if f == [] then Just(head l) else Just(head f)
where f = following x l
Now you can use 'next' this way :
> l = 2 : 5 : 6 : 1 : []
> next l 5
6
> next l 7
2
If you want to call next on a Maybe you can use the fact that a Maybe is a Monade.
> Just 5 >>= next l
Just 6
Note: I swapped the argument of next to make it easier to call it his way.
Upvotes: 2
Reputation: 105955
Lets call the element e
and the list xs
. It gets a lot easier if you drop all elements at the start which aren't equal to e
with dropWhile (/= e)
. Afterwards, you can focus on two cases, in which we will always return a value:
(_:y:_)
to get the element after e
and return y
Overall, we get
next :: Eq a => Maybe a -> [a] -> Maybe a
next _ [] = Nothing
next Nothing (x:_) = Just x
next (Just e) l@(x:_) = Just $ case dropWhile (/= e) l of
(_:y:_) -> y
_ -> x
Upvotes: 7