queuelike-1.0.7: Data/Semigroup.hs
{-# LANGUAGE MagicHash, UnboxedTuples, GeneralizedNewtypeDeriving, FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
module Data.Semigroup (Monoid(..), Endo, Fusion, Point(..), Semigroup(..), endoMaybe, endoPoint, fusing', fusing, fuseCat, scatPoints', scatPoints, pJust, pNothing) where
import Data.Monoid(Monoid(..))
import Data.Maybe
import GHC.Exts
type Endo a = a -> a -> a
type Fusion a = [a] -> Maybe a
newtype Point a = Pt (Maybe a) deriving (Functor, Eq, Show, Read)
class Semigroup a where
sappend :: Endo a
sconcat :: Fusion a
sconcat = fusing
sconcat_ :: a -> [a] -> a
sconcat_ x xs = fromJust (sconcat (x:xs))
instance Monoid a => Semigroup a where
sappend = mappend
sconcat = Just . mconcat
sconcat_ x xs = mconcat (x:xs)
{-instance Semigroup a => Semigroup (Maybe a) where
sappend = endoMaybe sappend
sconcat xs = Just (sconcat [x | Just x <- xs])-}
instance Semigroup a => Monoid (Point a) where
mempty = Pt Nothing
mappend = endoPoint sappend
mconcat = Pt . scatPoints
{-# INLINE [1] endoMaybe #-}
endoMaybe :: Endo a -> Endo (Maybe a)
endoMaybe (><) (Just a) = Just . maybe a (a ><)
endoMaybe _ Nothing = id
{-# RULES "endoMaybe/Just" forall f a b . endoMaybe f a (Just b) = Just (maybe b (`f` b) a) #-}
{-# INLINE endoPoint #-}
endoPoint :: Endo a -> Endo (Point a)
endoPoint (><) (Pt a) (Pt b) = Pt (endoMaybe (><) a b)
fusing' :: Endo a -> Fusion a
fusing' _ [] = Nothing
fusing' (><) (q:qs) = Just $ fuseCat (><) q qs
fuseCat :: Endo a -> a -> [a] -> a
fuseCat (><) = fuseCat' where
fuseCat' x [] = x
fuseCat' x xs = case fuse1 x xs of ( x', xs' ) -> fuseCat' x' xs'
fuse1 x1 (x2:x3:x4:xs) = ( (x1 >< x2) >< (x3 >< x4), fuser xs )
fuse1 x1 [x2,x3] = ( x1 >< x2 >< x3, [] )
fuse1 x1 [x2] = ( x1 >< x2, [] )
fuse1 x1 [] = ( x1, [] )
fuser [] = []
fuser (x:xs) = case fuse1 x xs of ( x, xs ) -> x:xs
fusing :: Semigroup a => Fusion a
fusing = fusing' sappend
{-# INLINE scatPoints' #-}
scatPoints' :: Fusion a -> [Point a] -> Maybe a
scatPoints' cat xs = cat [x | Pt (Just x) <- xs]
{-# INLINE scatPoints #-}
scatPoints :: Semigroup a => [Point a] -> Maybe a
scatPoints = scatPoints' sconcat
pJust :: a -> Point a
pJust = Pt . Just
pNothing :: Point a
pNothing = Pt Nothing