Reputation: 89
I want to return the preceding element of an element in list. I am intending to get the index of parameter and use it to deprecate list such that parameter is the last element, then reverse it and take the second element of reversed list.
I get error: type elemIndex
is Maybe Int
while take
function require Int
. I want to fix it or write code using simple recursion
Are there a shorter code using recursion?
precedingElement :: Eq a => a -> [a] -> Maybe a
precedingElement elt lst | lst == [] = error "List is empty"
| elt `notElem` lst = Nothing
| otherwise = Just x where x = snd (reverse (take (elt `elemIndex` lst) lst))
Upvotes: 2
Views: 1214
Reputation: 11
Sort-of standard solution for this is to use zipping:
import Data.List (find)
preceding :: (a -> Bool) -> [a] -> Maybe a
preceding f xs = fmap snd . find (f . fst) $ zip (drop 1 xs) xs
Upvotes: 1
Reputation: 43383
One of my favourite underappreciated utilities is rather handy for problems like this. Let me have backward lists, so I don't need to reverse my brain.
data Bwd x = B0 | Bwd x :< x -- rightmost is nearest
Think of list elements as the beads on an abacus wire. Flick a few to the left and leave your finger resting on the next one. What have you? A list of beads to the left of your finger (with the rightmost nearest), a list of beads to the right of your finger (with the leftmost nearest), and the bead with your finger on it.
That is, a one-hole element context for lists is given by the pair of backward and forward lists either side of the hole.
type ListContext x = (Bwd x, [x])
Those who know my old songs recognize ListContext
as the derivative of []
.
An element in focus (your finger on a bead) is
type ListFocus x = (ListContext x, x)
And there is a useful operation which decorates every list element with its context, putting it in focus.
focus :: [x] -> [ListFocus x]
focus = go B0 where
go xz [] = []
go xz (x : xs) = ((xz, xs), x) : go (xz :< x) xs
For example,
focus [1,2,3] = [((B0,[2,3]),1), ((B0 :< 1,[3]),2), ((B0 :< 1 :< 2,[]),3)]
and now it is very easy to answer all sorts of questions that concern an element and its immediate surroundings. You mightn't construct focus
just to solve this problem, but it's the sort of thing I keep around because it solves lots of problems.
[p | ((_ :< p,_),q) <- focus xs, q == x]
computes all the values p
which sit to the left of an x
in xs
. As you can see.
(By the way, this focus
operation didn't come from nowhere. It arises from the differential structure of the datatype of lists. This answer (where it is called picks
) tells the list story in more detail, and this answer develops the datatype generic story.)
Upvotes: 9
Reputation: 48591
As I'm a big fold fan, I might write something like
lastBefore :: (a -> Bool) -> [a] -> Maybe a
lastBefore p xs = foldr go (`seq` Nothing) xs Nothing
where
go x r (Just prev) | p x = Just prev
go x r _ = r (Just x)
But I'd have to check that GHC optimizes it as I wish.
Upvotes: 2
Reputation: 83527
In order to return the preceding element of the given element, you can use some pattern matching and recursion:
precedingElement _ [] = Nothing
precedingElement _ [x] = Nothing
precedingElement elt (x:y:rest)
| y == elt = Just x
| otherwise = precedingElement elt (y:rest)
Upvotes: 5