content: {-# LANGUAGE RankNTypes #-}
  
  module Data.Composeable
      ( Compose
      , compose
      , composeFold
      , composeM
      , composeOp
      , composeFoldM
      ) where
  
  import Data.Monoid
  import Control.Applicative
  import Control.Monad.Identity
  import Control.Monad.Writer
  
  class Compose t where
      compose :: Applicative f => (forall a. t a -> f (t a)) -> t c -> f (t c)
  
  composeFold :: (Monoid o, Compose t) => (forall a. t a -> o) -> t a -> o
  composeFold f = getConst . compose (Const . f)
  
  composeM :: (Monad m, Compose t) => (forall a. t a -> m (t a)) -> t a -> m (t a)
  composeM f = unwrapMonad . compose (WrapMonad . f)
  
  composeFoldM :: (Monoid o, Monad m, Compose t) => (forall a. t a -> m o) -> t a -> m o
  composeFoldM f = execWriterT . unwrapMonad . compose t
    where
      t structure = WrapMonad $ do
          x <- lift $ f structure
          tell x
          --return undefined -- would be as valid
          return structure
  
  composeOp :: Compose t => (forall k. t k -> t k) -> t k -> t k
  composeOp f = runIdentity . compose (Identity . f)
  