-- | A datatype of finite sequences module Test.Feat.Finite (Finite (..), Index, fromFinite, finFin) where import Control.Applicative import Data.Semigroup import Data.Monoid type Index = Integer data Finite a = Finite {fCard :: Index, fIndex :: Index -> a} finEmpty = Finite 0 (\i -> error "index: Empty") finUnion :: Finite a -> Finite a -> Finite a finUnion f1 f2 | fCard f1 == 0 = f2 | fCard f2 == 0 = f1 | otherwise = Finite car sel where car = fCard f1 + fCard f2 sel i = if i < fCard f1 then fIndex f1 i else fIndex f2 (i-fCard f1) instance Functor Finite where fmap f fin = fin{fIndex = f . fIndex fin} instance Applicative Finite where pure = finPure a <*> b = fmap (uncurry ($)) (finCart a b) instance Alternative Finite where empty = finEmpty (<|>) = finUnion instance Semigroup (Finite a) where (<>) = finUnion instance Monoid (Finite a) where mempty = finEmpty mappend = finUnion mconcat xs = Finite (sum $ map fCard xs) (sumSel $ filter ((>0) . fCard) xs) sumSel :: [Finite a] -> (Index -> a) sumSel (f:rest) = \i -> if i < fCard f then fIndex f i else sumSel rest (i-fCard f) sumSel _ = error "Index out of bounds" finCart :: Finite a -> Finite b -> Finite (a,b) finCart f1 f2 = Finite car sel where car = fCard f1 * fCard f2 sel i = let (q, r) = (i `quotRem` fCard f2) in (fIndex f1 q, fIndex f2 r) finPure :: a -> Finite a finPure a = Finite 1 one where one 0 = a one _ = error "Index out of bounds" fromFinite :: Finite a -> (Index,[a]) fromFinite (Finite c ix) = (c,map ix [0..c-1]) instance Show a => Show (Finite a) where show = show . fromFinite finFin :: Integer -> Finite Integer finFin k | k <= 0 = finEmpty finFin k = Finite k (\i -> i)