I'm writing a function that gets the index of the first even number from a list. The list I get may or may not contain even numbers, and I'd like to return -1 if there are no even numbers in the list. The list can be infinite.
I wrote this
posicPrimerPar'' :: [Int] -> Int
posicPrimerPar'' a = fromJust (elemIndex (head (filter (even) a)) a)
I could do something like:
posicPrimerPar' :: [Int] -> Int
posicPrimerPar' a = case length evens of
0 -> -1;
n -> fromJust elemIndex (head evens) a
where evens = filter (even) a
But as you can see, this is not the most efficient way of doing it. A list [1..100000]
contains a lot of even numbers, and I just need the first one. I need Haskell's laziness, so I need to ask for the head right there, but head throws an empty list exception when the list is empty (i.e. there are no even numbers in the list). I cannot find the Haskell equivalent of Python's try: ... except: ...
. All I could find regarding exceptions were IO related. What I need is except Prelude.head = -1
or something like that.
CodePudding user response:
Haskell is lazy, so evens
will not be fully evaluated. The problematic part is the length evens
which is not necessary. You can check with null :: Foldable f => f a -> Bool
, or with pattern matching. For example:
import Data.List(findIndex)
posicPrimerPar' :: [Int] -> Maybe Int
posicPrimerPar' [] = Nothing
posicPrimerPar' xs = findIndex even xs
for findIndex :: (a -> Bool) -> [a] -> Maybe Int
, you however do not need to take into account the empty list, since it already considers this.
or we can return -1
in case there is no such item:
import Data.List(findIndex)
import Data.Maybe(fromMaybe)
posicPrimerPar' :: [Int] -> Int
posicPrimerPar' = fromMaybe (-1) . findIndex even