-- | The most generic definitions for folding function applications. -- {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE UndecidableSuperClasses #-} 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 of constraints which feature a function to convert a value of -- one type to a value of another. -- class Converter (conv :: * -> * -> Constraint) where convert :: conv a b => a -> b -- instance Converter (~) where convert = id -- -- | Constrain all parameters of f to be convertible to p and the return -- of f to be r. -- 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 defining left-associative folds of function applications. No -- other instances need be defined. -- class ( Converter conv , Infer conv p r f ) => FoldlApp (conv :: * -> * -> Constraint) (p :: * ) (r :: * ) (f :: * ) where -- | Left-associative fold of function applications. 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)) -- -- | Monadic left-associative fold of function applications. -- 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 defining right-associative folds of function applications. No -- other instances need be defined. -- class ( Converter conv , Infer conv p r f ) => FoldrApp (conv :: * -> * -> Constraint) (p :: * ) (r :: * ) (f :: * ) where -- | Right-associative fold of function applications. This is an -- internal implementation; use 'foldrApp' instead. 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 -- -- | Right-associative fold of function applications. -- foldrApp :: forall conv p r f. FoldrApp conv p r f => (p -> r -> r) -> r -> f foldrApp f = foldrAppImpl @conv f id -- | Monadic right-associative fold of function applications. -- 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)