Reputation: 219
I have this function that returns the second largest value from a given list:
import Data.List
secondL :: Ord a => [a] -> a
secondL xs =
let x = head xs
in let find (a, b) x = (min b (max a x), max b x)
in fst (foldl find (x, x) xs)
This function should be working correctly, but for better purity I would like to exclude the function find
's definition which is inside, and rework this function so that there is no other function declaration inside.
I was thinking about including (min b (max a x), max b x)
into foldl
argument, but this doesn't seem to be working well.
Upvotes: 2
Views: 446
Reputation: 71119
listToMaybe . take 1 . drop 1 . sortBy (flip compare)
:: Ord a => [a] -> Maybe a
will do this for you. It is even linear, because Haskell is lazy, and Haskell's sort
is mergesort.
If you meant second largest, not second among the largest, you can just stick a nub
in there to get it:
listToMaybe . take 1 . drop 1 . nub . sortBy (flip compare)
:: Ord a => [a] -> Maybe a
It'll still be linear.
Trying it out:
> listToMaybe . take 1 . drop 1 . nub . sortBy (flip compare) $ [1,3,2,3,1]
Just 2
> listToMaybe . take 1 . drop 1 . nub . sortBy (flip compare) $ [3,3,3]
Nothing
(use https://hoogle.haskell.org/ to search for functions)
If you want to code it with left fold specifically, then
foo :: Ord a => [a] -> Maybe a
foo xs
| [_,y] <- foldl' g [] xs = Just y
| otherwise = Nothing
where
g ys x = take 2 . nub . reverse . sort $ x:ys
Writing g
out by hand with all the comparisons and the checks needed (or itself as a fold) is left as an exercise.
Upvotes: 3