content: -- |
  -- Module     : Unbound.Generics.LocallyNameless.Internal.Fold
  -- Copyright  : (c) 2014, Aleksey Kliger
  -- License    : BSD3 (See LICENSE)
  -- Maintainer : Aleksey Kliger
  -- Stability  : experimental
  --
  -- Some utilities for working with Folds.
  --
  -- If you are using <http://hackage.haskell.org/package/lens lens>, you don't need this module.
  {-# LANGUAGE RankNTypes #-}
  module Unbound.Generics.LocallyNameless.Internal.Fold (Fold, Traversal', toListOf, filtered, justFiltered, foldMapOf) where
  
  import Control.Applicative
  import Data.Maybe (fromJust)
  import Data.Functor.Contravariant
  import Data.Monoid
  
  type Getting r s a = (a -> Const r a) -> s -> Const r s
  
  type Fold s a = forall f . (Contravariant f, Applicative f) => (a -> f a) -> s -> f s
  
  type Traversal' s a = forall f . Applicative f => (a -> f a) -> s -> f s
  
  toListOf :: Fold s a -> s -> [a]
  -- toListOf :: Getting (Endo [a]) s a -> s -> [a]
  toListOf l = foldrOf l (:) []
  {-# INLINE toListOf #-}
  
  foldMapOf :: Getting r s a -> (a -> r) -> s -> r
  foldMapOf l f = getConst . l (Const . f)
  {-# INLINE foldMapOf #-}
  
  foldrOf :: Getting (Endo r) s a -> (a -> r -> r) -> r -> s -> r
  foldrOf l f z = fmap (flip appEndo z) (foldMapOf l (Endo .f))
  {-# INLINE foldrOf #-}
  
  filtered :: (a -> Bool) -> Traversal' a a
  filtered p afa x = if p x then afa x else pure x
  {-# INLINE filtered #-}
  
  justFiltered :: (a -> Maybe b) -> Fold a b
  justFiltered p bfb x = case p x of
                          Just b -> contramap (fromJust . p) (bfb b)
                          Nothing -> pure x
  {-# INLINE justFiltered #-}
  