folds-0.1: src/Data/Fold/M.hs
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ExistentialQuantification #-}
-- |
-- Unlike 'Data.Fold.L' and 'Data.Fold.R' this 'Comonad'
-- is based on a @(->) r@ 'Comonad' for a 'Monoid' @r@ rather than
-- than on the @'Store' r@ 'Comonad'.
module Data.Fold.M
( M(..)
) where
import Control.Applicative
import Control.Comonad
import Control.Lens
import Data.Fold.Class
import Data.Foldable hiding (sum, product)
import Data.Functor.Extend
import Data.Functor.Bind
import Data.Monoid
import Data.Profunctor.Unsafe
import Data.Proxy
import Data.Reflection
import Unsafe.Coerce
import Prelude hiding (sum, product, length)
-- | A 'foldMap' caught in amber.
data M a b = forall m. M (m -> b) (a -> m) (m -> m -> m) m
-- | efficient 'prefix', efficient 'postfix'
instance Folding M where
run s (M k h m (z :: m)) = reify (m, z) $
\ (_ :: Proxy s) -> k $ runN (foldMap (N #. h) s :: N m s)
run1 a (M k h _ _) = k (h a)
runOf l s (M k h m (z :: m)) = reify (m, z) $
\ (_ :: Proxy s) -> k $ runN (foldMapOf l (N #. h) s :: N m s)
prefix s (M k h m (z :: m)) = reify (m, z) $
\ (_ :: Proxy s) -> case runN (foldMap (N #. h) s :: N m s) of
x -> M (\y -> k (m x y)) h m z
prefix1 a (M k h m z) = case h a of
x -> M (\y -> k (m x y)) h m z
prefixOf l s (M k h m (z :: m)) = reify (m, z) $
\ (_ :: Proxy s) -> case runN (foldMapOf l (N #. h) s :: N m s) of
x -> M (\y -> k (m x y)) h m z
postfix (M k h m (z :: m)) s = reify (m, z) $
\ (_ :: Proxy s) -> case runN (foldMap (N #. h) s :: N m s) of
y -> M (\x -> k (m x y)) h m z
postfix1 (M k h m z) a = case h a of
y -> M (\x -> k (m x y)) h m z
postfixOf l (M k h m (z :: m)) s = reify (m, z) $
\ (_ :: Proxy s) -> case runN (foldMapOf l (N #. h) s :: N m s) of
y -> M (\x -> k (m x y)) h m z
instance Profunctor M where
dimap f g (M k h m e) = M (g.k) (h.f) m e
{-# INLINE dimap #-}
rmap g (M k h m e) = M (g.k) h m e
{-# INLINE rmap #-}
lmap f (M k h m e) = M k (h.f) m e
{-# INLINE lmap #-}
(#.) _ = unsafeCoerce
{-# INLINE (#.) #-}
x .# _ = unsafeCoerce x
{-# INLINE (.#) #-}
instance Choice M where
left' (M k h m z) = M (_Left %~ k) (_Left %~ h) step (Left z) where
step (Left x) (Left y) = Left (m x y)
step (Right c) _ = Right c
step _ (Right c) = Right c
{-# INLINE left' #-}
right' (M k h m z) = M (_Right %~ k) (_Right %~ h) step (Right z) where
step (Right x) (Right y) = Right (m x y)
step (Left c) _ = Left c
step _ (Left c) = Left c
{-# INLINE right' #-}
instance Functor (M a) where
fmap f (M k h m z) = M (f.k) h m z
{-# INLINE fmap #-}
(<$) b = \_ -> pure b
{-# INLINE (<$) #-}
instance Comonad (M a) where
extract (M k _ _ z) = k z
{-# INLINE extract #-}
duplicate (M k h m z) = M (\n -> M (k . m n) h m z) h m z
{-# INLINE duplicate #-}
data Pair a b = Pair !a !b
instance Applicative (M a) where
pure b = M (\() -> b) (\_ -> ()) (\() () -> ()) ()
{-# INLINE pure #-}
M xf bx xx xz <*> M ya by yy yz = M
(\(Pair x y) -> xf x $ ya y)
(\b -> Pair (bx b) (by b))
(\(Pair x1 y1) (Pair x2 y2) -> Pair (xx x1 x2) (yy y1 y2))
(Pair xz yz)
{-# INLINE (<*>) #-}
(<*) m = \_ -> m
{-# INLINE (<*) #-}
_ *> m = m
{-# INLINE (*>) #-}
instance Bind (M a) where
(>>-) = (>>=)
{-# INLINE (>>-) #-}
instance Monad (M a) where
return = pure
{-# INLINE return #-}
m >>= f = M (\xs a -> run xs (f a)) One Two Zero <*> m
{-# INLINE (>>=) #-}
instance Extend (M a) where
extended = extend
{-# INLINE extended #-}
duplicated = duplicate
{-# INLINE duplicated #-}
instance Apply (M a) where
(<.>) = (<*>)
{-# INLINE (<.>) #-}
(<.) m = \_ -> m
{-# INLINE (<.) #-}
_ .> m = m
{-# INLINE (.>) #-}
instance ComonadApply (M a) where
(<@>) = (<*>)
{-# INLINE (<@>) #-}
(<@) m = \_ -> m
{-# INLINE (<@) #-}
_ @> m = m
{-# INLINE (@>) #-}
-- * Internals
-- | A reified 'Monoid'.
newtype N a s = N { runN :: a }
instance Reifies s (a -> a -> a, a) => Monoid (N a s) where
mempty = N $ snd $ reflect (Proxy :: Proxy s)
{-# INLINE mempty #-}
mappend (N a) (N b) = N $ fst (reflect (Proxy :: Proxy s)) a b
{-# INLINE mappend #-}
-- | The shape of a 'foldMap'
data Tree a = Zero | One a | Two (Tree a) (Tree a)
instance Functor Tree where
fmap _ Zero = Zero
fmap f (One a) = One (f a)
fmap f (Two a b) = Two (fmap f a) (fmap f b)
instance Foldable Tree where
foldMap _ Zero = mempty
foldMap f (One a) = f a
foldMap f (Two a b) = foldMap f a `mappend` foldMap f b
instance Traversable Tree where
traverse _ Zero = pure Zero
traverse f (One a) = One <$> f a
traverse f (Two a b) = Two <$> traverse f a <*> traverse f b