{-# LANGUAGE TupleSections #-} module FoldableHelp ( safeMinimumOn , safeMinimumOnMaybe , safeMinimumOnMaybeF , safeMinimumOnMaybeL , safeMinMaybeL , module Data.Foldable ) where import Data.Foldable import qualified Control.Foldl as L -- TODO check up whether and how it is necessary to specialise this -- | A version of 'minimum' where the comparison is done on some extracted value. -- Returns Nothing if the list is empty. -- -- > safeMinimumOn id [] == Nothing -- > safeMinimumOn length ["test","extra","a"] == Just "a" safeMinimumOn :: (Foldable t,Ord b) => (a -> b) -> t a -> Maybe a {-# INLINE safeMinimumOn #-} safeMinimumOn f = foldl' g Nothing where g (Just x) y | f x < f y = Just x | otherwise = Just y g Nothing y = Just y safeMinimumOnMaybeF :: (Ord b) => (a -> Maybe b) -> [a] -> Maybe a safeMinimumOnMaybeF f = L.fold $ L.Fold step initial extract where initial = Nothing step Nothing x = (x ,) <$> f x step (Just (a,x)) b = case f b of Just y | y < x -> Just (b,y) _ -> Just (a,x) extract = fmap fst safeMinMaybeL :: (Ord b) => (a -> Maybe b) -> L.Fold a (Maybe b) safeMinMaybeL f = L.Fold step initial id where initial = Nothing step Nothing x = f x step (Just x) b = case f b of Just y | y < x -> Just y _ -> Just x safeMinimumOnMaybeL :: (Ord b) => (a -> Maybe b) -> L.Fold a (Maybe a) safeMinimumOnMaybeL f = L.Fold step initial extract where initial = Nothing step Nothing x = (x ,) <$> f x step (Just (a,x)) b = case f b of Just y | y < x -> Just (b,y) _ -> Just (a,x) extract = fmap fst safeMinimumOnMaybe :: (Ord b) => (a -> Maybe b) -> [a] -> Maybe a safeMinimumOnMaybe f ys = fst <$> go Nothing ys where go Nothing (x:xs) = go ((x ,) <$> f x) xs go (Just (y,cmin)) (x:xs) = case f x of Just v | v < cmin -> go (Just (x,v)) xs _ -> go (Just (y,cmin)) xs go m _ = m --{- | Partial. -} --minimumOn :: Ord b => (a -> b) -> [a] -> a --minimumOn f [] = error "tried to take minimumOn of empty list" --minimumOn f (x:xs) = go x xs -- where -- go x (y:xs) | f x < f y = go x xs -- | otherwise = go y xs -- go x [] = x