-- | == tying-the-knot principle for a lens like over behaviour on list partitions -- -- -- >>> onOdds (tail . cycle) [1..10] -- [3,2,5,4,7,6,9,8,1,10] -- -- module Data.List.OnPartition ( -- * general onPartitionG , -- * 'List' partition like onPartition , -- * by index onPartitionIndex , -- * simple ones onRights , onOdds ) where import Control.Arrow ((***)) import Control.Monad.Fix (fix) import Data.Bool (bool) -- | apply a function to the partitioned elements of a list, as a whole onPartition :: (a -> Bool) -- ^ partitioner -> ([a] -> [a]) -- ^ analyzer -> [a] -> [a] onPartition s = fmap (map $ either id id) . onPartitionG (flip (bool Left Right) <*> s) -- | apply a function to the inedex partitioned elements of a list, as a whole onPartitionIndex :: (Int -> Bool) -- ^ partitioner -> ([a] -> [a]) -- ^ analyzer -> [a] -> [a] onPartitionIndex s f = map snd . onPartition (s . fst) (uncurry zip . fmap f . unzip) . zip [0..] -- | apply a function to the partitioned elements of a list, as a whole, changing their types onPartitionG :: (d -> Either c a) -- ^ partitioner -> ([a] -> [b]) -- ^ analyzer -> [d] -> [Either c b] onPartitionG s f xs = fst . fix $ part xs . f . snd where part [] _ = ([],[]) part (x:xs) rt@(~(r:rs)) = case s x of Right x -> ((Right r:) *** (x:) $ part xs rs) Left y -> ((Left y:) *** id $ part xs rt) -- | apply a function to the Right elements of a list, as a whole, changing their types onRights :: ([a] -> [b]) -- ^ analyzer -> [Either l a] -> [Either l b] onRights = onPartitionG id -- | change the odds onOdds :: ([a] -> [a]) -- ^ analyzer -> [a] -> [a] onOdds = onPartitionIndex even