module Data.FoldApp.Generic
( Converter(convert)
, FoldlApp(foldlApp)
, FoldrApp()
, Monad
, foldlMApp
, foldrApp
, foldrMApp
)
where
import Control.Monad
( Monad((>>=), return)
)
import Data.Kind
( Constraint
)
import Prelude
( id
, flip
)
class Converter (conv :: * -> * -> Constraint) where
convert :: conv a b => a -> b
instance Converter (~) where
convert = id
type family
Infer (conv :: * -> * -> Constraint)
(p :: * )
(r :: * )
(f :: * )
:: Constraint
where
Infer conv p r (a -> f) = (conv a p, Infer conv p r f)
Infer _ _ r s = r ~ s
class
( Converter conv
, Infer conv p r f
) =>
FoldlApp (conv :: * -> * -> Constraint)
(p :: * )
(r :: * )
(f :: * )
where
foldlApp :: (r -> p -> r) -> r -> f
instance (Converter conv, Infer conv p r r) => FoldlApp conv p r r where
foldlApp _ r = r
instance
( Converter conv
, Infer conv p r (x -> f)
, FoldlApp conv p r f
) =>
FoldlApp conv p r (x -> f)
where
foldlApp f r p = foldlApp @conv f (f r (convert @conv p))
foldlMApp ::
forall conv m p r f.
(Monad m, FoldlApp conv p (m r) f) =>
(r -> p -> m r) -> r -> f
foldlMApp f r = foldlApp @conv (\r' p -> r' >>= flip f p) (return r)
class
( Converter conv
, Infer conv p r f
) =>
FoldrApp (conv :: * -> * -> Constraint)
(p :: * )
(r :: * )
(f :: * )
where
foldrAppImpl :: (p -> r -> r) -> (r -> r) -> r -> f
instance (Converter conv, Infer conv p r r) => FoldrApp conv p r r where
foldrAppImpl _ g r = g r
instance
( Converter conv
, Infer conv p r (x -> f)
, FoldrApp conv p r f
) => FoldrApp conv p r (x -> f)
where
foldrAppImpl f g r p =
foldrAppImpl @conv f (\r' -> g (f (convert @conv p) r')) r
foldrApp ::
forall conv p r f.
FoldrApp conv p r f =>
(p -> r -> r) -> r -> f
foldrApp f = foldrAppImpl @conv f id
foldrMApp ::
forall conv m p r f.
(Monad m, FoldrApp conv p (m r) f) =>
(p -> r -> m r) -> r -> f
foldrMApp f r = foldrApp @conv (\p r' -> r' >>= f p) (return r)