{-# LANGUAGE FlexibleInstances, FunctionalDependencies, MultiParamTypeClasses, StandaloneDeriving, TypeSynonymInstances #-} {-# OPTIONS_GHC -Wall -Werror #-} module Distribution.Package.Debian.Interspersed ( Interspersed(..) ) where import Debug.Trace -- | A class of Bs insterspersed with Cs. Minimum implementation is a -- method to return the leftmost B, and another to return the -- following (C,B) pairs. Its unfortunate to require lists in the -- implementation, a fold function would be better (though I find -- implementing such folds to be a pain in the you-know-what.) -- -- The class provides implementations of three folds, each of which -- exposes slightly different views of the data. class Interspersed t around between | t -> around, t -> between where leftmost :: t -> around pairs :: t -> [(between, around)] foldTriples :: (around -> between -> around -> r -> r) -> r -> t -> r foldTriples f r0 x = snd $ foldl (\ (b1, r) (c, b2) -> (b2, f b1 c b2 r)) (leftmost x, r0) (pairs x) -- Treat the b's as the centers and the c's as the things to their -- left and right. Use Maybe to make up for the missing c's at the -- ends. foldInverted :: (Maybe between -> around -> Maybe between -> r -> r) -> r -> t -> r foldInverted f r0 x = (\ (bn, an, r) -> f bn an Nothing r) $ foldl g (Nothing, leftmost x, r0) (pairs x) where g (b1, a1, r) (b2, a2) = (Just b2, a2, f b1 a1 (Just b2) r) foldArounds :: (around -> around -> r -> r) -> r -> t -> r foldArounds f r0 x = snd $ foldl (\ (a1, r) (_, a2) -> (a2, f a1 a2 r)) (leftmost x, r0) (pairs x) foldBetweens :: (between -> r -> r) -> r -> t -> r foldBetweens f r0 x = foldl (\ r (b, _) -> (f b r)) r0 (pairs x) -- | An example data Splits = Splits Double [(String, Double)] deriving Show instance Interspersed Splits Double String where leftmost (Splits x _) = x pairs (Splits _ x) = x _splits :: Splits _splits = Splits 1.0 [("between 1 and 2", 2.0), ("between 2 and 3", 3.0)] _test1 :: () _test1 = foldTriples (\ l s r () -> trace ("l=" ++ show l ++ " s=" ++ show s ++ " r=" ++ show r) ()) () _splits _test2 :: () _test2 = foldInverted (\ sl f sr () -> trace ("sl=" ++ show sl ++ " f=" ++ show f ++ " sr=" ++ show sr) ()) () _splits