free-functors 0.8.3 → 0.8.4
raw patch · 5 files changed
+138/−145 lines, 5 filesdep ~algebraic-classesdep ~basedep ~constraints
Dependency ranges changed: algebraic-classes, base, constraints, contravariant, template-haskell
Files
- CHANGELOG +7/−0
- free-functors.cabal +5/−5
- src/Data/Constraint/Class1.hs +4/−2
- src/Data/Functor/Free.hs +7/−116
- src/Data/Functor/Free/TH.hs +115/−22
CHANGELOG view
@@ -1,5 +1,12 @@ CHANGELOG +0.8.3 -> 0.8.4+ - Updated to constraints-0.10+ - Updated for GHC 8.4+ - Updated to base-4.11+ - Updated to template-haskell-2.13+ - `Semigroup` is now a superclass of `Monoid`+ 0.8.2 -> 0.8.3 - Added Data.Functor.Free.TH to other-modules
free-functors.cabal view
@@ -1,5 +1,5 @@ name: free-functors-version: 0.8.3+version: 0.8.4 synopsis: Free functors, adjoint to functors that forget class constraints. description: A free functor is a left adjoint to a forgetful functor. It used to be the case that the only category that was easy to work with in Haskell was Hask itself, so@@ -47,12 +47,12 @@ Haskell2010 build-depends:- base >= 4.9 && < 4.11,- template-haskell >= 2.11 && < 2.13,- constraints == 0.9.*,+ base == 4.11.*,+ template-haskell == 2.13.*,+ constraints == 0.10.*, transformers == 0.5.*, comonad == 5.*,- algebraic-classes >= 0.9 && < 1.0,+ algebraic-classes == 0.9.*, contravariant == 1.4.*, bifunctors == 5.*, profunctors == 5.*
src/Data/Constraint/Class1.hs view
@@ -35,7 +35,6 @@ import Data.Functor.Contravariant import Data.Functor.Contravariant.Divisible import Data.Profunctor-import Data.Semigroup -- | Proof that @b@ is a superclass of @h@, i.e. @h x@ entails @b x@. scls1 :: forall b h x. SuperClass1 b h => h x :- b x@@ -89,7 +88,10 @@ superClasses = Sub Dict containsSelf = Sub Dict instance HasSuperClasses Semigroup-instance HasSuperClasses Monoid+instance HasSuperClasses Monoid where+ type SuperClasses Monoid = Monoid ': SuperClasses Semigroup+ superClasses = Sub Dict+ containsSelf = Sub Dict instance HasSuperClasses Functor instance HasSuperClasses Applicative where
src/Data/Functor/Free.hs view
@@ -1,3 +1,4 @@+{-# OPTIONS_GHC -fno-warn-orphans #-} {-# LANGUAGE ConstraintKinds , GADTs@@ -56,73 +57,14 @@ ) where -import Control.Comonad import Data.Function-import Data.Semigroup -import Data.Constraint hiding (Class)-import Data.Constraint.Forall-import Data.Constraint.Class1--import Data.Foldable (Foldable(..))-import Data.Traversable import Data.Void -import Data.Algebra import Language.Haskell.TH.Syntax import Data.Functor.Free.TH ---- | The free functor for class @c@.------ @Free c a@ is basically an expression tree with operations from class @c@--- and variables/placeholders of type @a@, created with `unit`.--- Monadic bind allows you to replace each of these variables with another sub-expression.-newtype Free c a = Free { runFree :: forall b. c b => (a -> b) -> b }---- | `unit` allows you to create @`Free` c@ values, together with the operations from the class @c@.-unit :: a -> Free c a-unit a = Free $ \k -> k a---- | `rightAdjunct` is the destructor of @`Free` c@ values.-rightAdjunct :: c b => (a -> b) -> Free c a -> b-rightAdjunct f g = runFree g f--rightAdjunctF :: ForallF c f => (a -> f b) -> Free c a -> f b-rightAdjunctF = h instF rightAdjunct- where- h :: ForallF c f- => (ForallF c f :- c (f b))- -> (c (f b) => (a -> f b) -> Free c a -> f b)- -> (a -> f b) -> Free c a -> f b- h (Sub Dict) f = f--class ForallLifted c where- dictLifted :: Applicative f => Dict (c (LiftAFree c f a))--rightAdjunctLifted :: (ForallLifted c, Applicative f) => (a -> LiftAFree c f b) -> Free c a -> LiftAFree c f b-rightAdjunctLifted = h dictLifted rightAdjunct- where- h :: Dict (c (t f b))- -> (c (t f b) => (a -> t f b) -> Free c a -> t f b)- -> (a -> t f b) -> Free c a -> t f b- h Dict f = f---- | @counit = rightAdjunct id@-counit :: c a => Free c a -> a-counit = rightAdjunct id---- | @leftAdjunct f = f . unit@-leftAdjunct :: (Free c a -> b) -> a -> b-leftAdjunct f = f . unit---- | @transform f as = as >>= f unit@------ @transform f . transform g = transform (g . f)@-transform :: (forall r. c r => (b -> r) -> a -> r) -> Free c a -> Free c b-transform t (Free f) = Free (f . t)- -- | @unfold f = coproduct (unfold f) unit . f@ -- -- `inL` and `inR` are useful here. For example, the following creates the list @[1..10]@ as a @Free Monoid@:@@ -139,33 +81,7 @@ convertClosed :: c r => Free c Void -> r convertClosed = rightAdjunct absurd -instance Functor (Free c) where- fmap f = transform (. f) -instance Applicative (Free c) where- pure = unit- fs <*> as = transform (\k f -> rightAdjunct (k . f) as) fs--instance Monad (Free c) where- return = unit- as >>= f = transform (\k -> rightAdjunct k . f) as--newtype Extract a = Extract { getExtract :: a }-newtype Duplicate f a = Duplicate { getDuplicate :: f (f a) }-instance (ForallF c Extract, ForallF c (Duplicate (Free c)))- => Comonad (Free c) where- extract = getExtract . rightAdjunctF Extract- duplicate = getDuplicate . rightAdjunctF (Duplicate . unit . unit)--instance SuperClass1 (Class f) c => Algebra f (Free c a) where- algebra fa = Free $ \k -> h scls1 (fmap (rightAdjunct k) fa)- where- h :: c b => (c b :- Class f b) -> f b -> b- h (Sub Dict) = evaluate- --- -- | Products of @Monoid@s are @Monoid@s themselves. But coproducts of @Monoid@s are not. -- However, the free @Monoid@ applied to the coproduct /is/ a @Monoid@, and it is the coproduct in the category of @Monoid@s. -- This is also called the free product, and generalizes to any algebraic class.@@ -186,41 +102,16 @@ initial = rightAdjunct absurd --newtype LiftAFree c f a = LiftAFree { getLiftAFree :: f (Free c a) }--instance (Applicative f, SuperClass1 (Class s) c) => Algebra s (LiftAFree c f a) where- algebra = LiftAFree . fmap algebra . traverse getLiftAFree--instance ForallLifted c => Foldable (Free c) where- foldMap = foldMapDefault--instance ForallLifted c => Traversable (Free c) where- traverse f = getLiftAFree . rightAdjunctLifted (LiftAFree . fmap unit . f)---data ShowHelper f a = ShowUnit a | ShowRec (f (ShowHelper f a))--instance Algebra f (ShowHelper f a) where- algebra = ShowRec--instance (Show a, Show (f (ShowHelper f a))) => Show (ShowHelper f a) where- showsPrec p (ShowUnit a) = showParen (p > 10) $ showString "unit " . showsPrec 11 a- showsPrec p (ShowRec f) = showsPrec p f--instance (Show a, Show (Signature c (ShowHelper (Signature c) a)), c (ShowHelper (Signature c) a)) => Show (Free c a) where- showsPrec p = showsPrec p . rightAdjunct (ShowUnit :: a -> ShowHelper (Signature c) a)- -- | Derive the instances of @`Free` c a@ for the class @c@, `Show`, `Foldable` and `Traversable`. -- -- For example: -- -- @deriveInstances ''Num@ deriveInstances :: Name -> Q [Dec]-deriveInstances = deriveInstances' True ''ForallLifted 'dictLifted ''Free ''LiftAFree ''ShowHelper+deriveInstances = deriveInstances' True -deriveInstances' False ''ForallLifted 'dictLifted ''Free ''LiftAFree ''ShowHelper ''Num-deriveInstances' False ''ForallLifted 'dictLifted ''Free ''LiftAFree ''ShowHelper ''Fractional-deriveInstances' False ''ForallLifted 'dictLifted ''Free ''LiftAFree ''ShowHelper ''Floating-deriveInstances' False ''ForallLifted 'dictLifted ''Free ''LiftAFree ''ShowHelper ''Semigroup-deriveInstances' False ''ForallLifted 'dictLifted ''Free ''LiftAFree ''ShowHelper ''Monoid+deriveInstances' False ''Num+deriveInstances' False ''Fractional+deriveInstances' False ''Floating+deriveInstances' False ''Semigroup+deriveInstances' False ''Monoid
src/Data/Functor/Free/TH.hs view
@@ -18,12 +18,116 @@ import Data.Constraint hiding (Class) import Data.Constraint.Class1+import Data.Constraint.Forall +import Control.Comonad+import Data.Algebra import Data.Algebra.TH import Language.Haskell.TH.Syntax+import Data.Traversable -deriveInstances' :: Bool -> Name -> Name -> Name -> Name -> Name -> Name -> Q [Dec]-deriveInstances' withHSC forallLiftedNm dictLiftedNm freeNm liftAFreeNm showHelperNm nm = getSignatureInfo nm >>= h where+-- | The free functor for class @c@.+--+-- @Free c a@ is basically an expression tree with operations from class @c@+-- and variables/placeholders of type @a@, created with `unit`.+-- Monadic bind allows you to replace each of these variables with another sub-expression.+newtype Free c a = Free { runFree :: forall b. c b => (a -> b) -> b }++-- | `unit` allows you to create @`Free` c@ values, together with the operations from the class @c@.+unit :: a -> Free c a+unit a = Free $ \k -> k a++-- | `rightAdjunct` is the destructor of @`Free` c@ values.+rightAdjunct :: c b => (a -> b) -> Free c a -> b+rightAdjunct f g = runFree g f++rightAdjunctF :: ForallF c f => (a -> f b) -> Free c a -> f b+rightAdjunctF = h instF rightAdjunct+ where+ h :: ForallF c f+ => (ForallF c f :- c (f b))+ -> (c (f b) => (a -> f b) -> Free c a -> f b)+ -> (a -> f b) -> Free c a -> f b+ h (Sub Dict) f = f++-- | @counit = rightAdjunct id@+counit :: c a => Free c a -> a+counit = rightAdjunct id++-- | @leftAdjunct f = f . unit@+leftAdjunct :: (Free c a -> b) -> a -> b+leftAdjunct f = f . unit++-- | @transform f as = as >>= f unit@+--+-- @transform f . transform g = transform (g . f)@+transform :: (forall r. c r => (b -> r) -> a -> r) -> Free c a -> Free c b+transform t (Free f) = Free (f . t)+++instance Functor (Free c) where+ fmap f = transform (. f)++instance Applicative (Free c) where+ pure = unit+ fs <*> as = transform (\k f -> rightAdjunct (k . f) as) fs++instance Monad (Free c) where+ return = unit+ as >>= f = transform (\k -> rightAdjunct k . f) as++newtype Extract a = Extract { getExtract :: a }+newtype Duplicate f a = Duplicate { getDuplicate :: f (f a) }+instance (ForallF c Extract, ForallF c (Duplicate (Free c)))+ => Comonad (Free c) where+ extract = getExtract . rightAdjunctF Extract+ duplicate = getDuplicate . rightAdjunctF (Duplicate . unit . unit)+ ++class ForallLifted c where+ dictLifted :: Applicative f => Dict (c (LiftAFree c f a))++rightAdjunctLifted :: (ForallLifted c, Applicative f) => (a -> LiftAFree c f b) -> Free c a -> LiftAFree c f b+rightAdjunctLifted = h dictLifted rightAdjunct+ where+ h :: Dict (c (t f b))+ -> (c (t f b) => (a -> t f b) -> Free c a -> t f b)+ -> (a -> t f b) -> Free c a -> t f b+ h Dict f = f++newtype LiftAFree c f a = LiftAFree { getLiftAFree :: f (Free c a) }++instance SuperClass1 (Class f) c => Algebra f (Free c a) where+ algebra fa = Free $ \k -> h scls1 (fmap (rightAdjunct k) fa)+ where+ h :: c b => (c b :- Class f b) -> f b -> b+ h (Sub Dict) = evaluate+ +instance (Applicative f, SuperClass1 (Class s) c) => Algebra s (LiftAFree c f a) where+ algebra = LiftAFree . fmap algebra . traverse getLiftAFree++instance ForallLifted c => Foldable (Free c) where+ foldMap = foldMapDefault++instance ForallLifted c => Traversable (Free c) where+ traverse f = getLiftAFree . rightAdjunctLifted (LiftAFree . fmap unit . f)+++data ShowHelper f a = ShowUnit a | ShowRec (f (ShowHelper f a))++instance Algebra f (ShowHelper f a) where+ algebra = ShowRec++instance (Show a, Show (f (ShowHelper f a))) => Show (ShowHelper f a) where+ showsPrec p (ShowUnit a) = showParen (p > 10) $ showString "unit " . showsPrec 11 a+ showsPrec p (ShowRec f) = showsPrec p f++instance (Show a, Show (Signature c (ShowHelper (Signature c) a)), c (ShowHelper (Signature c) a)) => Show (Free c a) where+ showsPrec p = showsPrec p . rightAdjunct (ShowUnit :: a -> ShowHelper (Signature c) a)+++deriveInstances' :: Bool -> Name -> Q [Dec]+deriveInstances' withHSC nm = getSignatureInfo nm >>= h where h sigInfo = concat <$> sequenceA [ deriveSignature nm@@ -32,28 +136,17 @@ , deriveInstanceWith_skipSignature showHelperHeader $ return [] , deriveSuperclassInstances showHelperHeader , hasSuperClassesInstance- , return $ [InstanceD Nothing [] (AppT (ConT forallLiftedNm) c) [ValD (VarP dictLiftedNm) (NormalB (ConE 'Dict)) []]]+ , [d|instance ForallLifted $c where dictLifted = Dict|] ] where- freeHeader = return $ ForallT [PlainTV a, PlainTV vc] [AppT (AppT superClass1 c) (VarT vc)]- (AppT c (AppT (AppT free (VarT vc)) (VarT a)))- liftAFreeHeader = return $ ForallT [PlainTV f, PlainTV a, PlainTV vc] [AppT (ConT ''Applicative) (VarT f), isSC]- (AppT c (AppT (AppT (AppT liftAFree (VarT vc)) (VarT f)) (VarT a)))- showHelperHeader = return $ ForallT [PlainTV a] []- (AppT c (AppT (AppT showHelper sig) (VarT a)))- hasSuperClassesInstance = if withHSC then [d|instance HasSuperClasses $(pure c) where {- type SuperClasses $(pure c) = $(pure c) ': $(scs);+ freeHeader = [t|forall a vc. SuperClass1 $c vc => $c (Free vc a)|]+ liftAFreeHeader = [t|forall f a vc. (Applicative f, SuperClass1 $c vc) => $c (LiftAFree vc f a)|]+ showHelperHeader = [t|forall a. $c (ShowHelper $sig a)|]+ hasSuperClassesInstance = if withHSC then [d|instance HasSuperClasses $c where {+ type SuperClasses $c = $c ': $scs; superClasses = Sub Dict; containsSelf = Sub Dict }|] else return []- scs = foldr (\(SuperclassTH scnm _ _) q -> [t|SuperClasses $(pure (ConT scnm)) ++ $(q)|]) [t|'[]|] $ superclasses sigInfo- isSC = AppT (AppT superClass1 c) (VarT vc)- free = ConT freeNm- liftAFree = ConT liftAFreeNm- showHelper = ConT showHelperNm- superClass1 = ConT ''SuperClass1- c = ConT nm- sig = ConT $ signatureName sigInfo- a = mkName "a"- f = mkName "f"- vc = mkName "c"+ scs = foldr (\(SuperclassTH scnm _ _) q -> [t|SuperClasses $(pure (ConT scnm)) ++ $q|]) [t|'[]|] $ superclasses sigInfo+ c = pure $ ConT nm+ sig = pure . ConT $ signatureName sigInfo