Reputation: 132
I want to write a code in Haskell, to return an element just before the occurrence of another element in a list. For ex:
eBefore 3 [1,2,3,4,5] should return 2
I am quiet new to haskell. The code that i've written up till now is :
eBefore :: Eq a => a -> [a] -> Maybe a
eBefore n [] = Nothing
eBefore n (x:xs) = if x == n then Just x else eBefore n xs
I would be highly obliged if some one could help me understand the approach or help me out with the problem. Thank you!
Upvotes: 0
Views: 392
Reputation: 2373
You can match more elaborated patterns:
eBefore n [] = Nothing
eBefore n [_] = Nothing
eBefore n (x1:xs@(x2:_))
| x2 == n = Just x1
| otherwise = eBefore n xs
Here we return Nothing
for lists containing zero or one elements because they contain no member with another one preceding them. (x1:xs@(x2:_))
is a pattern that matches a x1:xs
, where xs
in turn matches x2:_
, that is, a list with at least two elements, the first element is bound to x1
, the second to x2
, the residue is unimportant (matched by _
).
We also might write thus:
eBefore n [] = Nothing
eBefore n [_] = Nothing
eBefore n (x1:x2:xs)
| x2 == n = Just x1
| otherwise = eBefore n (x2:xs)
However, this variant might be worse in terms of performance. (x1:x2:xs)
is equivalent to (x1:(x2:xs))
, and we see that (x2:xs)
repeated again as an argument to recursive call. But the compiler may fail to recognize the identity of the two expressions and create a new node. That's a waste. By using the @
-notation in the former variant, we give that (x2:_)
from the pattern a name, xs
, and pass it to the recursive call as a ready whole.
The difficult moment here is what we should return in case n
is equal to the head of the list, e. g. eBefore 3 [3,4,5,6,3]
. The definition above will skip the first occurrence of 3 and return 6.
Upvotes: 2