free-category 0.0.3.0 → 0.0.4.0
raw patch · 15 files changed
+1827/−337 lines, 15 filesdep +QuickCheckdep +criteriondep +free-categorydep ~basedep ~free-algebrasPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: QuickCheck, criterion, free-category, tasty, tasty-quickcheck
Dependency ranges changed: base, free-algebras
API changes (from Hackage documentation)
- Control.Category.Free: [Id] :: Cat f a a
- Control.Category.Free: arrCat :: forall (f :: k -> k -> *) a b. f a b -> Cat f a b
- Control.Category.Free: data Cat (f :: k -> k -> *) a b
- Control.Category.Free: foldCat :: forall f c a b. Category c => (forall x y. f x y -> c x y) -> Cat f a b -> c a b
- Control.Category.Free: instance Control.Algebra.Free2.FreeAlgebra2 Control.Category.Free.Cat
- Control.Category.Free: instance Control.Arrow.Arrow f => Control.Arrow.Arrow (Control.Category.Free.Cat f)
- Control.Category.Free: instance Control.Arrow.ArrowChoice f => Control.Arrow.ArrowChoice (Control.Category.Free.Cat f)
- Control.Category.Free: instance Control.Arrow.ArrowZero f => Control.Arrow.ArrowZero (Control.Category.Free.Cat f)
- Control.Category.Free: instance forall k (f :: k -> k -> *) (o :: k). GHC.Base.Monoid (Control.Category.Free.Cat f o o)
- Control.Category.Free: instance forall k (f :: k -> k -> *) (o :: k). GHC.Base.Semigroup (Control.Category.Free.Cat f o o)
- Control.Category.Free: instance forall k (f :: k -> k -> *). Control.Category.Category (Control.Category.Free.Cat f)
- Control.Category.Free: mapCat :: forall (f :: k -> k -> *) a b c. f b c -> Cat f a b -> Cat f a c
- Control.Category.Free.Internal: cons :: forall (f :: k -> k -> *) a b c. f b c -> Queue f a b -> Queue f a c
- Control.Category.Free.Internal: emptyQ :: Queue (f :: k -> k -> *) a a
- Control.Category.Free.Internal: foldQ :: forall (f :: k -> k -> *) c a b. Category c => (forall x y. f x y -> c x y) -> Queue f a b -> c a b
- Control.Category.Free.Internal: snoc :: forall (f :: k -> k -> *) a b c. Queue f b c -> f a b -> Queue f a c
- Control.Category.Free.Internal: uncons :: Queue f a b -> ViewL f a b
- Control.Category.FreeEff: [Base] :: c a b -> FreeEffCat m c a b
- Control.Category.FreeEff: [Lift] :: m (FreeEffCat m c a b) -> FreeEffCat m c a b
- Control.Category.FreeEff: class Category c => EffCategory c m | c -> m
- Control.Category.FreeEff: data FreeEffCat :: (* -> *) -> (k -> k -> *) -> k -> k -> *
- Control.Category.FreeEff: foldNatLift :: (Monad m, EffCategory c m) => (forall x y. tr x y -> c x y) -> FreeEffCat m (Cat tr) a b -> c a b
- Control.Category.FreeEff: instance Control.Category.FreeEff.EffCategory (->) Data.Functor.Identity.Identity
- Control.Category.FreeEff: instance GHC.Base.Monad m => Control.Algebra.Free2.FreeAlgebra2 (Control.Category.FreeEff.FreeEffCat m)
- Control.Category.FreeEff: instance GHC.Base.Monad m => Control.Category.FreeEff.EffCategory (Control.Arrow.Kleisli m) m
- Control.Category.FreeEff: instance forall k (m :: * -> *) (c :: k -> k -> *). (GHC.Base.Functor m, Control.Category.Category c) => Control.Category.Category (Control.Category.FreeEff.FreeEffCat m c)
- Control.Category.FreeEff: instance forall k (m :: * -> *) (c :: k -> k -> *). (GHC.Base.Functor m, Control.Category.Category c) => Control.Category.FreeEff.EffCategory (Control.Category.FreeEff.FreeEffCat m c) m
- Control.Category.FreeEff: lift :: EffCategory c m => m (c a b) -> c a b
- Control.Category.FreeEff: liftCat :: Monad m => tr a b -> FreeEffCat m (Cat tr) a b
- Control.Category.FreeEff: liftKleisli :: Applicative m => (a -> b) -> Kleisli m a b
+ Control.Category.Free: [ConsTr] :: f b c -> ListTr f a b -> ListTr f a c
+ Control.Category.Free: [NilTr] :: ListTr f a a
+ Control.Category.Free: consC :: forall (f :: k -> k -> *) a b c. f b c -> C f a b -> C f a c
+ Control.Category.Free: consQ :: forall (f :: k -> k -> *) a b c. f b c -> Queue f a b -> Queue f a c
+ Control.Category.Free: data ListTr :: (k -> k -> *) -> k -> k -> *
+ Control.Category.Free: data Queue (f :: k -> k -> *) (a :: k) (b :: k)
+ Control.Category.Free: foldNatC :: forall (f :: k -> k -> *) c a b. Category c => (forall x y. f x y -> c x y) -> C f a b -> c a b
+ Control.Category.Free: foldNatL :: forall (f :: k -> k -> *) c a b. Category c => (forall x y. f x y -> c x y) -> ListTr f a b -> c a b
+ Control.Category.Free: foldNatQ :: forall (f :: k -> k -> *) c a b. Category c => (forall x y. f x y -> c x y) -> Queue f a b -> c a b
+ Control.Category.Free: foldlL :: forall (f :: k -> k -> *) c a b d. (forall x y z. c y z -> f x y -> c x z) -> c b d -> ListTr f a b -> c a d
+ Control.Category.Free: foldlQ :: forall (f :: k -> k -> *) c a b d. (forall x y z. c y z -> f x y -> c x z) -> c b d -> Queue f a b -> c a d
+ Control.Category.Free: foldrL :: forall (f :: k -> k -> *) c a b d. (forall x y z. f y z -> c x y -> c x z) -> c a b -> ListTr f b d -> c a d
+ Control.Category.Free: foldrQ :: forall (f :: k -> k -> *) c a b d. (forall x y z. f y z -> c x y -> c x z) -> c a b -> Queue f b d -> c a d
+ Control.Category.Free: hoistFreeH2 :: (FreeAlgebra2 m, FreeAlgebra2 n, AlgebraType0 m f, AlgebraType0 n f, AlgebraType m (n f)) => m f a b -> n f a b
+ Control.Category.Free: hoistOp :: forall (f :: k -> k -> *) (g :: k -> k -> *) a b. (forall x y. f x y -> g x y) -> Op f a b -> Op g a b
+ Control.Category.Free: instance forall k (f :: k -> k -> *) (a :: k) (b :: k). (forall (x :: k) (y :: k). GHC.Show.Show (f x y)) => GHC.Show.Show (Control.Category.Free.C f a b)
+ Control.Category.Free: liftC :: forall (f :: k -> k -> *) a b. f a b -> C f a b
+ Control.Category.Free: liftL :: forall (f :: k -> k -> *) x y. f x y -> ListTr f x y
+ Control.Category.Free: liftQ :: forall (f :: k -> k -> *) a b. f a b -> Queue f a b
+ Control.Category.Free: pattern ConsQ :: f b c -> Queue f a b -> Queue f a c
+ Control.Category.Free: pattern NilQ :: () => a ~ b => Queue f a b
+ Control.Category.Free: snocQ :: forall (f :: k -> k -> *) a b c. Queue f b c -> f a b -> Queue f a c
+ Control.Category.Free: unconsQ :: Queue f a b -> ViewL f a b
+ Control.Category.Free: zipWithL :: forall f g a b a' b'. Category f => (forall x y x' y'. f x y -> f x' y' -> f (g x x') (g y y')) -> ListTr f a b -> ListTr f a' b' -> ListTr f (g a a') (g b b')
+ Control.Category.Free: zipWithQ :: forall f g a b a' b'. Category f => (forall x y x' y'. f x y -> f x' y' -> f (g x x') (g y y')) -> Queue f a b -> Queue f a' b' -> Queue f (g a a') (g b b')
+ Control.Category.Free.Internal: [:<] :: f b c -> Queue f a b -> ViewL f a c
+ Control.Category.Free.Internal: [EmptyL] :: ViewL f a a
+ Control.Category.Free.Internal: consQ :: forall (f :: k -> k -> *) a b c. f b c -> Queue f a b -> Queue f a c
+ Control.Category.Free.Internal: data ViewL f a b
+ Control.Category.Free.Internal: foldNatL :: forall (f :: k -> k -> *) c a b. Category c => (forall x y. f x y -> c x y) -> ListTr f a b -> c a b
+ Control.Category.Free.Internal: foldNatQ :: forall (f :: k -> k -> *) c a b. Category c => (forall x y. f x y -> c x y) -> Queue f a b -> c a b
+ Control.Category.Free.Internal: foldlL :: forall (f :: k -> k -> *) c a b d. (forall x y z. c y z -> f x y -> c x z) -> c b d -> ListTr f a b -> c a d
+ Control.Category.Free.Internal: foldlQ :: forall (f :: k -> k -> *) c a b d. (forall x y z. c y z -> f x y -> c x z) -> c b d -> Queue f a b -> c a d
+ Control.Category.Free.Internal: foldrL :: forall (f :: k -> k -> *) c a b d. (forall x y z. f y z -> c x y -> c x z) -> c a b -> ListTr f b d -> c a d
+ Control.Category.Free.Internal: foldrQ :: forall (f :: k -> k -> *) c a b d. (forall x y z. f y z -> c x y -> c x z) -> c a b -> Queue f b d -> c a d
+ Control.Category.Free.Internal: hoistOp :: forall (f :: k -> k -> *) (g :: k -> k -> *) a b. (forall x y. f x y -> g x y) -> Op f a b -> Op g a b
+ Control.Category.Free.Internal: hoistQ :: forall (f :: k -> k -> *) (g :: k -> k -> *) a b. (forall x y. f x y -> g x y) -> Queue f a b -> Queue g a b
+ Control.Category.Free.Internal: instance Control.Algebra.Free2.FreeAlgebra2 Control.Category.Free.Internal.Queue
+ Control.Category.Free.Internal: instance Control.Arrow.Arrow f => Control.Arrow.Arrow (Control.Category.Free.Internal.Queue f)
+ Control.Category.Free.Internal: instance Control.Arrow.ArrowChoice f => Control.Arrow.ArrowChoice (Control.Category.Free.Internal.Queue f)
+ Control.Category.Free.Internal: instance Control.Arrow.ArrowZero f => Control.Arrow.ArrowZero (Control.Category.Free.Internal.Queue f)
+ Control.Category.Free.Internal: instance forall k (f :: k -> k -> *) (a :: k) (b :: k). (forall (x :: k) (y :: k). GHC.Show.Show (f x y)) => GHC.Show.Show (Control.Category.Free.Internal.ListTr f a b)
+ Control.Category.Free.Internal: instance forall k (f :: k -> k -> *) (a :: k) (b :: k). (forall (x :: k) (y :: k). GHC.Show.Show (f x y)) => GHC.Show.Show (Control.Category.Free.Internal.Queue f a b)
+ Control.Category.Free.Internal: instance forall k (f :: k -> k -> *) (a :: k) (b :: k). GHC.Show.Show (f b a) => GHC.Show.Show (Control.Category.Free.Internal.Op f a b)
+ Control.Category.Free.Internal: instance forall k (f :: k -> k -> *) (o :: k). GHC.Base.Monoid (Control.Category.Free.Internal.Queue f o o)
+ Control.Category.Free.Internal: instance forall k (f :: k -> k -> *) (o :: k). GHC.Base.Semigroup (Control.Category.Free.Internal.Queue f o o)
+ Control.Category.Free.Internal: instance forall k (f :: k -> k -> *). Control.Category.Category (Control.Category.Free.Internal.Queue f)
+ Control.Category.Free.Internal: lengthListTr :: ListTr f a b -> Int
+ Control.Category.Free.Internal: liftL :: forall (f :: k -> k -> *) x y. f x y -> ListTr f x y
+ Control.Category.Free.Internal: liftQ :: forall (f :: k -> k -> *) a b. f a b -> Queue f a b
+ Control.Category.Free.Internal: nilQ :: Queue (f :: k -> k -> *) a a
+ Control.Category.Free.Internal: snocQ :: forall (f :: k -> k -> *) a b c. Queue f b c -> f a b -> Queue f a c
+ Control.Category.Free.Internal: unconsQ :: Queue f a b -> ViewL f a b
+ Control.Category.Free.Internal: zipWithL :: forall f g a b a' b'. Category f => (forall x y x' y'. f x y -> f x' y' -> f (g x x') (g y y')) -> ListTr f a b -> ListTr f a' b' -> ListTr f (g a a') (g b b')
+ Control.Category.FreeEffect: [Base] :: c a b -> EffCat m c a b
+ Control.Category.FreeEffect: [Effect] :: m (EffCat m c a b) -> EffCat m c a b
+ Control.Category.FreeEffect: class Category c => EffectCategory c m | c -> m
+ Control.Category.FreeEffect: data EffCat :: (* -> *) -> (k -> k -> *) -> k -> k -> *
+ Control.Category.FreeEffect: effect :: EffectCategory c m => m (c a b) -> c a b
+ Control.Category.FreeEffect: foldNatEffCat :: (Monad m, FreeAlgebra2 cat, AlgebraType cat c, AlgebraType0 cat tr, Category (cat tr), EffectCategory c m) => (forall x y. tr x y -> c x y) -> EffCat m (cat tr) a b -> c a b
+ Control.Category.FreeEffect: instance Control.Category.FreeEffect.EffectCategory (->) Data.Functor.Identity.Identity
+ Control.Category.FreeEffect: instance GHC.Base.Monad m => Control.Algebra.Free2.FreeAlgebra2 (Control.Category.FreeEffect.EffCat m)
+ Control.Category.FreeEffect: instance GHC.Base.Monad m => Control.Category.FreeEffect.EffectCategory (Control.Arrow.Kleisli m) m
+ Control.Category.FreeEffect: instance forall k (m :: * -> *) (c :: k -> k -> *). (GHC.Base.Functor m, Control.Category.Category c) => Control.Category.Category (Control.Category.FreeEffect.EffCat m c)
+ Control.Category.FreeEffect: instance forall k (m :: * -> *) (c :: k -> k -> *). (GHC.Base.Functor m, Control.Category.Category c) => Control.Category.FreeEffect.EffectCategory (Control.Category.FreeEffect.EffCat m c) m
+ Control.Category.FreeEffect: liftEffect :: (Monad m, FreeAlgebra2 cat, AlgebraType0 cat tr, Category (cat tr)) => tr a b -> EffCat m (cat tr) a b
+ Control.Category.FreeEffect: liftKleisli :: Applicative m => (a -> b) -> Kleisli m a b
- Control.Category.Free.Internal: zipWithQ :: forall f g a b a' b'. Arrow f => (forall x y x' y'. f x y -> f x' y' -> f (g x x') (g y y')) -> Queue f a b -> Queue f a' b' -> Queue f (g a a') (g b b')
+ Control.Category.Free.Internal: zipWithQ :: forall f g a b a' b'. Category f => (forall x y x' y'. f x y -> f x' y' -> f (g x x') (g y y')) -> Queue f a b -> Queue f a' b' -> Queue f (g a a') (g b b')
Files
- ChangeLog.md +14/−2
- README.md +20/−10
- bench/Main.hs +187/−0
- bench/report-O0.md +126/−0
- bench/report-O1.md +129/−0
- bench/report-O2.md +126/−0
- free-category.cabal +48/−4
- src/Control/Arrow/Free.hs +9/−9
- src/Control/Category/Free.hs +125/−137
- src/Control/Category/Free/Internal.hs +406/−86
- src/Control/Category/FreeEff.hs +0/−89
- src/Control/Category/FreeEffect.hs +97/−0
- test/Main.hs +17/−0
- test/Test/Cat.hs +410/−0
- test/Test/Queue.hs +113/−0
ChangeLog.md view
@@ -1,5 +1,19 @@ # Changelog for free-category +## Version 0.0.4.0+- hoistOp+- Renamed `Control.Category.FreeEff` module as `Control.Category.FreeEffect`+ and renamed top level terms:+ - `EffCategory` type class to `EffectCategory`+ - `FreeEffCat` to `EffCat`+ - `FreeEffCat` constructor as `Effect` and `lift` as `effect`+ - `liftCat` to `liftEffect`+ - `foldNatLift` to `foldNatEffCat`+- Show instance of 'Cat' and 'C' via 'ListTr' (GHC >= 806)+- Performance optimisations: rewrite rules & inline pragmas+- Export ListTr from Control.Category.Free+- foldrL, foldlL and zipWithL+ ## Version 0.0.3.0 - Efficient 'Cat' and 'Aff' based on real time queues with scheduling - Added Monoid instances @@ -15,5 +29,3 @@ ## Version 0.0.1.0 - free category (concrete and condensity transformed) - free arrows (concrete and condensity transformed)--## Unreleased changes
README.md view
@@ -2,21 +2,31 @@ [](http://github.com/coot) [](https://circleci.com/gh/coot/free-category/tree/master) -This package contains efficient free categories. There are two presentations:+This package contains efficient implementations of free categories. There are+various representations available: -* using realtime queues (C. Okasaki 'Pure Functional Data Structures')-* using continuation passing style+* real-time queues (C. Okasaki 'Pure Functional Data Structures')+* type aligned lists+* continuation passing style (Church encoding) Free arrows and free Kleisli categories are also included. Free categories are useful to model state machines in a simple yet type safe-manner. For that purpose `Kleisli` categroies are a very useful target which-allows to include monadic computations. This packge contains a useful-generalisation of `Kliesli` categories captured by `EffCategory` class-(effectful categories), and a (free) transformer which lifts a category to-an effectful one.+manner. For that purpose `Kleisli` categories are a very useful target which+allows to include monadic computations. This package contains a useful+generalisation of `Kliesli` categories captured by `EffectCategory` class+(categories with effects), and a (free) transformer which lifts a category to+a category with effects. -## Some examples+## Benchmarks++Check performance characteristics of various representations:++* [report-O0](/bench/report-O0.md)+* [report-O1](/bench/report-O1.md)+* [report-O2](/bench/report-O2.md)++## Resources * [LoginStateMachine](https://github.com/coot/free-category/blob/master/examples/src/LoginStateMachine.hs): based on [State Machines All The Way Down](https://www.youtube.com/watch?v=xq7ZuSRgCR4) by Edwin Bradly, 2017 You@@ -26,4 +36,4 @@ using a simple GADT. * Another [example](https://github.com/coot/free-algebras/blob/master/examples/src/Control/Category/Free.hs).-* [Blog post](https://coot.me/posts/kleisli-categories-and-free-monads.html) on Keleisli categories.+* [Blog post](https://coot.me/posts/kleisli-categories-and-free-monads.html) on Kleisli categories.
+ bench/Main.hs view
@@ -0,0 +1,187 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE GADTs #-}++module Main where++import Prelude hiding (id, (.))+import Control.Category+import Data.Foldable (foldl')++import Control.Category.Free+import Control.Category.Free.Internal++import Criterion+import Criterion.Main+++data Alg a b where+ Add :: !Int -> Alg Int Int+ Mul :: !Int -> Alg Int Int++instance Show (Alg a b) where+ show (Add i) = "Add " ++ show i+ show (Mul i) = "Mul " ++ show i++interpret :: Alg a b -> a -> b+interpret (Add i) = (+i)+interpret (Mul i) = (*i)++-- foldr on outer and inner lists+fromListR :: Category (f Alg) => (Int -> f Alg Int Int) -> [[Int]] -> f Alg Int Int+fromListR f = foldr (\is c -> foldr (\i c' -> f i . c') id is . c) id++-- foldr on outer and foldl on inner list+fromListRL :: Category (f Alg) => (Int -> f Alg Int Int) -> [[Int]] -> f Alg Int Int+fromListRL f = foldr (\is c -> foldl (\c' i -> c' . f i) id is . c) id++-- foldl on outer and inner loop+fromListL :: Category (f Alg) => (Int -> f Alg Int Int) -> [[Int]] -> f Alg Int Int+fromListL f = foldl' (\c is -> c . foldl' (\c' i -> c' . f i) id is) id++-- foldl on outer and foldr on inner loop+fromListLR :: Category (f Alg) => (Int -> f Alg Int Int) -> [[Int]] -> f Alg Int Int+fromListLR f = foldr (\is c -> foldl' (\c' i -> c' . f i) id is . c) id++-- alternate foldl and foldr+fromListM' :: Category (f Alg) => (Int -> f Alg Int Int) -> [Int] -> f Alg Int Int+fromListM' f is = foldl' (\c (i, x) -> if x then c . f i+ else f i . c)+ id (zip is (concat $ repeat [True, False]))++-- alternate foldl and foldr+fromListM :: Category (f Alg) => (Int -> f Alg Int Int) -> [[Int]] -> f Alg Int Int+fromListM f iss = foldl' (\c (is, x) -> if x then c . fromListM' f is+ else fromListM' f is . c)+ id (zip iss (concat $ repeat [True, False]))++setupEnv100 :: [[Int]]+setupEnv100 = replicate 100 [1..100]++setupEnv250 :: [[Int]]+setupEnv250 = replicate 250 [1..250]++setupEnv500 :: [[Int]]+setupEnv500 = replicate 500 [1..500]++main :: IO ()+main = defaultMain+ [ env (pure setupEnv100) $ \ints -> bgroup "main"+ [ bgroup "Queue 100"+ [ bench "right right" $+ whnf+ (\c -> foldNatQ interpret c 0)+ (fromListR (\i -> liftQ (Add i)) ints)+ , bench "right left" $+ whnf+ (\c -> foldNatQ interpret c 0)+ (fromListRL (\i -> liftQ (Add i)) ints)+ , bench "left left " $+ whnf+ (\c -> foldNatQ interpret c 0)+ (fromListL (\i -> liftQ (Add i)) ints)+ , bench "left right" $+ whnf+ (\c -> foldNatQ interpret c 0)+ (fromListLR (\i -> liftQ (Add i)) ints)+ , bench "alternate " $+ whnf+ (\c -> foldNatQ interpret c 0)+ (fromListM (\i -> liftQ (Add i)) ints)+ ]++ , bgroup "ListTr 100"+ [ bench "right right" $+ whnf+ (\c -> foldNatL interpret c 0)+ (fromListR (\i -> liftL (Add i)) ints)+ , bench "right left" $+ whnf+ (\c -> foldNatL interpret c 0)+ (fromListRL (\i -> liftL (Add i)) ints)+ , bench "left left " $+ whnf+ (\c -> foldNatL interpret c 0)+ (fromListL (\i -> liftL (Add i)) ints)+ , bench "left right" $+ whnf+ (\c -> foldNatL interpret c 0)+ (fromListLR (\i -> liftL (Add i)) ints)+ , bench "alternate " $+ whnf+ (\c -> foldNatL interpret c 0)+ (fromListM (\i -> ConsTr (Add i) NilTr) ints)+ ]++ , bgroup "C 100"+ [ bench "right right" $+ whnf+ (\c -> foldNatFree2 interpret c 0)+ (fromListR ((\i -> C $ \k -> k (Add i))) ints)+ , bench "right left" $+ whnf+ (\c -> foldNatFree2 interpret c 0)+ (fromListRL ((\i -> C $ \k -> k (Add i))) ints)+ , bench "left left" $+ whnf+ (\c -> foldNatFree2 interpret c 0)+ (fromListL ((\i -> C $ \k -> k (Add i))) ints)+ , bench "left right" $+ whnf+ (\c -> foldNatFree2 interpret c 0)+ (fromListLR ((\i -> C $ \k -> k (Add i))) ints)+ , bench "alternate" $+ whnf+ (\c -> foldNatFree2 interpret c 0)+ (fromListM ((\i -> C $ \k -> k (Add i))) ints)+ ]+ ]+ , env (pure setupEnv250) $ \ints -> bgroup "main"+ [ bgroup "Queue 250"+ [ bench "right right" $+ whnf+ (\c -> foldNatQ interpret c 0)+ (fromListR (\i -> liftQ (Add i)) ints)+ ]++ , bgroup "ListTr 250"+ [ bench "right right" $+ whnf+ (\c -> foldNatL interpret c 0)+ (fromListR (\i -> liftL (Add i)) ints)+ ]++ {--+ - , bgroup "C 250"+ - [ bench "right right" $+ - whnf+ - (\c -> foldNatFree2 interpret c 0)+ - (fromListR ((\i -> C $ \k -> k (Add i))) ints)+ - ]+ --}+ ]+ , env (pure setupEnv500) $ \ints -> bgroup "main"+ [ bgroup "Queue 500"+ [ bench "right right" $+ whnf+ (\c -> foldNatQ interpret c 0)+ (fromListR (\i -> liftQ (Add i)) ints)+ ]++ , bgroup "ListTr 500"+ [ bench "right right" $+ whnf+ (\c -> foldNatL interpret c 0)+ (fromListR (\i -> liftL (Add i)) ints)+ ]++ {--+ - , bgroup "C 500"+ - [ bench "right right" $+ - whnf+ - (\c -> foldNatFree2 interpret c 0)+ - (fromListR ((\i -> C $ \k -> k (Add i))) ints)+ - ]+ --}+ ]+ ]+
+ bench/report-O0.md view
@@ -0,0 +1,126 @@+```+cabal run -O0 bench-cats +benchmarking main/Queue 100/right right+time 1.141 ms (1.138 ms .. 1.143 ms)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 1.140 ms (1.138 ms .. 1.143 ms)+std dev 8.646 μs (6.948 μs .. 11.22 μs)++benchmarking main/Queue 100/right left+time 1.141 ms (1.136 ms .. 1.147 ms)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 1.138 ms (1.135 ms .. 1.142 ms)+std dev 10.92 μs (8.393 μs .. 15.79 μs)++benchmarking main/Queue 100/left left +time 1.142 ms (1.139 ms .. 1.146 ms)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 1.142 ms (1.138 ms .. 1.147 ms)+std dev 14.64 μs (11.59 μs .. 19.91 μs)++benchmarking main/Queue 100/left right+time 1.141 ms (1.136 ms .. 1.147 ms)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 1.141 ms (1.137 ms .. 1.148 ms)+std dev 16.67 μs (9.879 μs .. 29.72 μs)++benchmarking main/Queue 100/alternate +time 1.164 ms (1.153 ms .. 1.185 ms)+ 0.983 R² (0.951 R² .. 0.999 R²)+mean 1.188 ms (1.159 ms .. 1.290 ms)+std dev 158.9 μs (71.22 μs .. 324.6 μs)+variance introduced by outliers: 83% (severely inflated)++benchmarking main/ListTr 100/right right+time 700.0 μs (691.4 μs .. 706.7 μs)+ 0.997 R² (0.993 R² .. 0.999 R²)+mean 756.8 μs (718.7 μs .. 906.9 μs)+std dev 245.7 μs (9.661 μs .. 523.4 μs)+variance introduced by outliers: 97% (severely inflated)++benchmarking main/ListTr 100/right left+time 756.6 μs (717.7 μs .. 812.2 μs)+ 0.980 R² (0.959 R² .. 1.000 R²)+mean 719.7 μs (710.8 μs .. 755.0 μs)+std dev 48.82 μs (9.722 μs .. 100.7 μs)+variance introduced by outliers: 57% (severely inflated)++benchmarking main/ListTr 100/left left +time 767.3 μs (723.7 μs .. 813.2 μs)+ 0.983 R² (0.968 R² .. 1.000 R²)+mean 733.7 μs (723.2 μs .. 762.2 μs)+std dev 51.61 μs (22.86 μs .. 96.08 μs)+variance introduced by outliers: 59% (severely inflated)++benchmarking main/ListTr 100/left right+time 717.4 μs (715.5 μs .. 719.9 μs)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 718.1 μs (716.1 μs .. 721.1 μs)+std dev 7.838 μs (5.645 μs .. 12.14 μs)++benchmarking main/ListTr 100/alternate +time 715.4 μs (712.1 μs .. 720.6 μs)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 715.6 μs (713.4 μs .. 719.0 μs)+std dev 8.725 μs (6.633 μs .. 11.88 μs)++benchmarking main/C 100/right right+time 899.4 μs (894.7 μs .. 905.2 μs)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 902.1 μs (898.5 μs .. 906.9 μs)+std dev 13.97 μs (10.79 μs .. 19.73 μs)++benchmarking main/C 100/right left+time 903.2 μs (895.5 μs .. 911.5 μs)+ 0.999 R² (0.999 R² .. 1.000 R²)+mean 900.8 μs (896.2 μs .. 909.6 μs)+std dev 20.72 μs (14.03 μs .. 33.73 μs)+variance introduced by outliers: 13% (moderately inflated)++benchmarking main/C 100/left left+time 1.213 ms (1.199 ms .. 1.241 ms)+ 0.982 R² (0.955 R² .. 0.999 R²)+mean 1.236 ms (1.204 ms .. 1.320 ms)+std dev 159.4 μs (51.06 μs .. 269.7 μs)+variance introduced by outliers: 81% (severely inflated)++benchmarking main/C 100/left right+time 898.3 μs (854.1 μs .. 969.1 μs)+ 0.970 R² (0.951 R² .. 0.992 R²)+mean 925.6 μs (903.9 μs .. 959.2 μs)+std dev 89.03 μs (60.65 μs .. 138.8 μs)+variance introduced by outliers: 72% (severely inflated)++benchmarking main/C 100/alternate+time 1.075 ms (1.063 ms .. 1.093 ms)+ 0.996 R² (0.992 R² .. 0.999 R²)+mean 1.085 ms (1.071 ms .. 1.109 ms)+std dev 58.94 μs (35.22 μs .. 85.70 μs)+variance introduced by outliers: 43% (moderately inflated)++benchmarking main/Queue 250/right right+time 8.210 ms (8.158 ms .. 8.283 ms)+ 1.000 R² (0.999 R² .. 1.000 R²)+mean 8.104 ms (8.050 ms .. 8.148 ms)+std dev 141.8 μs (100.5 μs .. 213.6 μs)++benchmarking main/ListTr 250/right right+time 6.835 ms (6.677 ms .. 7.059 ms)+ 0.997 R² (0.994 R² .. 1.000 R²)+mean 6.631 ms (6.592 ms .. 6.697 ms)+std dev 151.1 μs (73.51 μs .. 274.0 μs)++benchmarking main/Queue 500/right right+time 33.14 ms (32.12 ms .. 34.38 ms)+ 0.995 R² (0.984 R² .. 0.999 R²)+mean 33.84 ms (33.06 ms .. 34.85 ms)+std dev 1.819 ms (1.173 ms .. 2.736 ms)+variance introduced by outliers: 18% (moderately inflated)++benchmarking main/ListTr 500/right right+time 28.88 ms (27.92 ms .. 30.42 ms)+ 0.983 R² (0.944 R² .. 0.999 R²)+mean 29.04 ms (28.51 ms .. 30.34 ms)+std dev 1.758 ms (608.9 μs .. 3.384 ms)+variance introduced by outliers: 21% (moderately inflated)+```
+ bench/report-O1.md view
@@ -0,0 +1,129 @@+```+cabal run -O1 bench-cats +benchmarking main/Queue 100/right right+time 344.2 μs (337.1 μs .. 362.0 μs)+ 0.974 R² (0.923 R² .. 1.000 R²)+mean 346.8 μs (338.8 μs .. 375.4 μs)+std dev 47.04 μs (4.662 μs .. 98.23 μs)+variance introduced by outliers: 87% (severely inflated)++benchmarking main/Queue 100/right left+time 334.1 μs (333.3 μs .. 334.7 μs)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 333.7 μs (333.1 μs .. 334.3 μs)+std dev 2.083 μs (1.686 μs .. 2.609 μs)++benchmarking main/Queue 100/left left +time 336.6 μs (334.3 μs .. 340.4 μs)+ 0.997 R² (0.991 R² .. 1.000 R²)+mean 339.0 μs (335.2 μs .. 353.2 μs)+std dev 20.23 μs (6.119 μs .. 45.16 μs)+variance introduced by outliers: 55% (severely inflated)++benchmarking main/Queue 100/left right+time 334.4 μs (333.9 μs .. 335.0 μs)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 334.3 μs (333.6 μs .. 335.3 μs)+std dev 2.840 μs (2.002 μs .. 4.592 μs)++benchmarking main/Queue 100/alternate +time 333.4 μs (332.9 μs .. 334.1 μs)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 334.1 μs (333.5 μs .. 334.7 μs)+std dev 1.989 μs (1.597 μs .. 2.655 μs)++benchmarking main/ListTr 100/right right+time 168.0 μs (167.7 μs .. 168.3 μs)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 168.4 μs (168.1 μs .. 168.9 μs)+std dev 1.328 μs (905.4 ns .. 2.041 μs)++benchmarking main/ListTr 100/right left+time 176.4 μs (173.7 μs .. 180.5 μs)+ 0.985 R² (0.966 R² .. 0.999 R²)+mean 180.4 μs (174.5 μs .. 191.0 μs)+std dev 26.56 μs (11.94 μs .. 40.58 μs)+variance introduced by outliers: 90% (severely inflated)++benchmarking main/ListTr 100/left left +time 181.4 μs (171.8 μs .. 200.9 μs)+ 0.965 R² (0.926 R² .. 1.000 R²)+mean 174.4 μs (171.5 μs .. 188.0 μs)+std dev 17.44 μs (1.898 μs .. 39.71 μs)+variance introduced by outliers: 80% (severely inflated)++benchmarking main/ListTr 100/left right+time 171.7 μs (170.3 μs .. 173.4 μs)+ 0.999 R² (0.999 R² .. 0.999 R²)+mean 175.3 μs (173.9 μs .. 177.5 μs)+std dev 5.737 μs (3.819 μs .. 10.35 μs)+variance introduced by outliers: 30% (moderately inflated)++benchmarking main/ListTr 100/alternate +time 172.2 μs (169.5 μs .. 174.3 μs)+ 0.999 R² (0.999 R² .. 1.000 R²)+mean 170.3 μs (169.6 μs .. 171.4 μs)+std dev 2.847 μs (2.192 μs .. 3.745 μs)++benchmarking main/C 100/right right+time 741.9 μs (720.1 μs .. 769.8 μs)+ 0.996 R² (0.993 R² .. 0.999 R²)+mean 738.5 μs (733.4 μs .. 746.4 μs)+std dev 21.90 μs (14.74 μs .. 36.25 μs)+variance introduced by outliers: 20% (moderately inflated)++benchmarking main/C 100/right left+time 671.2 μs (655.1 μs .. 693.1 μs)+ 0.974 R² (0.924 R² .. 0.999 R²)+mean 681.5 μs (658.5 μs .. 777.3 μs)+std dev 127.4 μs (26.16 μs .. 280.5 μs)+variance introduced by outliers: 92% (severely inflated)++benchmarking main/C 100/left left+time 802.2 μs (784.7 μs .. 824.5 μs)+ 0.996 R² (0.996 R² .. 0.998 R²)+mean 795.6 μs (787.1 μs .. 805.5 μs)+std dev 30.72 μs (26.91 μs .. 35.57 μs)+variance introduced by outliers: 29% (moderately inflated)++benchmarking main/C 100/left right+time 657.8 μs (650.4 μs .. 668.8 μs)+ 0.998 R² (0.997 R² .. 0.999 R²)+mean 656.8 μs (649.6 μs .. 665.1 μs)+std dev 26.63 μs (20.92 μs .. 35.68 μs)+variance introduced by outliers: 33% (moderately inflated)++benchmarking main/C 100/alternate+time 1.065 ms (1.053 ms .. 1.082 ms)+ 0.997 R² (0.994 R² .. 0.999 R²)+mean 1.074 ms (1.061 ms .. 1.093 ms)+std dev 53.90 μs (39.80 μs .. 70.25 μs)+variance introduced by outliers: 39% (moderately inflated)++benchmarking main/Queue 250/right right+time 3.203 ms (2.938 ms .. 3.591 ms)+ 0.966 R² (0.942 R² .. 0.998 R²)+mean 2.963 ms (2.915 ms .. 3.067 ms)+std dev 226.0 μs (94.89 μs .. 422.7 μs)+variance introduced by outliers: 52% (severely inflated)++benchmarking main/ListTr 250/right right+time 3.265 ms (3.231 ms .. 3.295 ms)+ 0.999 R² (0.999 R² .. 1.000 R²)+mean 3.261 ms (3.239 ms .. 3.284 ms)+std dev 71.15 μs (57.97 μs .. 86.47 μs)++benchmarking main/Queue 500/right right+time 11.72 ms (11.47 ms .. 11.94 ms)+ 0.997 R² (0.996 R² .. 0.999 R²)+mean 11.95 ms (11.79 ms .. 12.20 ms)+std dev 521.0 μs (333.3 μs .. 799.6 μs)+variance introduced by outliers: 17% (moderately inflated)++benchmarking main/ListTr 500/right right+time 17.55 ms (15.86 ms .. 18.15 ms)+ 0.956 R² (0.839 R² .. 0.999 R²)+mean 18.91 ms (18.14 ms .. 22.44 ms)+std dev 3.166 ms (347.5 μs .. 6.963 ms)+variance introduced by outliers: 71% (severely inflated)+```
+ bench/report-O2.md view
@@ -0,0 +1,126 @@+```+cabal run -O2 bench-cats +benchmarking main/Queue 100/right right+time 341.9 μs (341.2 μs .. 342.8 μs)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 340.9 μs (340.0 μs .. 341.9 μs)+std dev 3.115 μs (2.201 μs .. 4.603 μs)++benchmarking main/Queue 100/right left+time 342.2 μs (341.6 μs .. 342.8 μs)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 341.5 μs (340.9 μs .. 342.2 μs)+std dev 2.108 μs (1.700 μs .. 2.556 μs)++benchmarking main/Queue 100/left left +time 341.5 μs (341.1 μs .. 342.2 μs)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 341.9 μs (341.2 μs .. 343.3 μs)+std dev 3.117 μs (1.865 μs .. 5.348 μs)++benchmarking main/Queue 100/left right+time 344.0 μs (342.7 μs .. 345.8 μs)+ 1.000 R² (0.999 R² .. 1.000 R²)+mean 344.5 μs (343.2 μs .. 346.5 μs)+std dev 5.442 μs (4.365 μs .. 7.546 μs)++benchmarking main/Queue 100/alternate +time 359.1 μs (343.2 μs .. 378.1 μs)+ 0.989 R² (0.979 R² .. 0.999 R²)+mean 347.1 μs (343.3 μs .. 357.3 μs)+std dev 19.80 μs (10.27 μs .. 35.11 μs)+variance introduced by outliers: 53% (severely inflated)++benchmarking main/ListTr 100/right right+time 175.0 μs (174.3 μs .. 176.0 μs)+ 0.999 R² (0.999 R² .. 1.000 R²)+mean 175.8 μs (174.8 μs .. 178.3 μs)+std dev 5.004 μs (2.051 μs .. 9.617 μs)+variance introduced by outliers: 24% (moderately inflated)++benchmarking main/ListTr 100/right left+time 175.2 μs (174.2 μs .. 176.4 μs)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 175.3 μs (174.6 μs .. 176.2 μs)+std dev 2.866 μs (2.014 μs .. 4.405 μs)++benchmarking main/ListTr 100/left left +time 178.8 μs (175.7 μs .. 182.2 μs)+ 0.998 R² (0.998 R² .. 1.000 R²)+mean 177.0 μs (175.6 μs .. 179.9 μs)+std dev 6.350 μs (3.620 μs .. 11.78 μs)+variance introduced by outliers: 33% (moderately inflated)++benchmarking main/ListTr 100/left right+time 174.2 μs (173.3 μs .. 175.6 μs)+ 0.999 R² (0.998 R² .. 0.999 R²)+mean 180.9 μs (178.4 μs .. 184.9 μs)+std dev 10.83 μs (7.423 μs .. 16.29 μs)+variance introduced by outliers: 59% (severely inflated)++benchmarking main/ListTr 100/alternate +time 173.9 μs (173.0 μs .. 175.0 μs)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 173.5 μs (173.0 μs .. 174.1 μs)+std dev 1.951 μs (1.514 μs .. 2.633 μs)++benchmarking main/C 100/right right+time 798.5 μs (792.7 μs .. 803.5 μs)+ 1.000 R² (0.999 R² .. 1.000 R²)+mean 797.5 μs (793.5 μs .. 800.9 μs)+std dev 11.98 μs (9.948 μs .. 15.01 μs)++benchmarking main/C 100/right left+time 679.3 μs (670.8 μs .. 691.7 μs)+ 0.998 R² (0.997 R² .. 0.998 R²)+mean 686.6 μs (678.4 μs .. 695.5 μs)+std dev 27.59 μs (25.17 μs .. 30.52 μs)+variance introduced by outliers: 32% (moderately inflated)++benchmarking main/C 100/left left+time 780.6 μs (776.9 μs .. 783.9 μs)+ 1.000 R² (1.000 R² .. 1.000 R²)+mean 775.6 μs (772.1 μs .. 778.7 μs)+std dev 10.92 μs (8.476 μs .. 15.08 μs)++benchmarking main/C 100/left right+time 601.6 μs (598.7 μs .. 604.4 μs)+ 1.000 R² (0.999 R² .. 1.000 R²)+mean 607.9 μs (602.8 μs .. 616.0 μs)+std dev 20.49 μs (15.07 μs .. 26.09 μs)+variance introduced by outliers: 25% (moderately inflated)++benchmarking main/C 100/alternate+time 1.045 ms (987.6 μs .. 1.161 ms)+ 0.940 R² (0.867 R² .. 0.999 R²)+mean 1.016 ms (986.8 μs .. 1.107 ms)+std dev 152.4 μs (57.42 μs .. 296.9 μs)+variance introduced by outliers: 86% (severely inflated)++benchmarking main/Queue 250/right right+time 2.733 ms (2.700 ms .. 2.764 ms)+ 0.999 R² (0.999 R² .. 1.000 R²)+mean 2.694 ms (2.676 ms .. 2.710 ms)+std dev 56.66 μs (45.91 μs .. 76.23 μs)++benchmarking main/ListTr 250/right right+time 3.356 ms (3.175 ms .. 3.551 ms)+ 0.979 R² (0.968 R² .. 0.989 R²)+mean 3.425 ms (3.315 ms .. 3.587 ms)+std dev 422.6 μs (296.3 μs .. 610.7 μs)+variance introduced by outliers: 74% (severely inflated)++benchmarking main/Queue 500/right right+time 11.27 ms (10.84 ms .. 11.78 ms)+ 0.985 R² (0.973 R² .. 0.993 R²)+mean 12.36 ms (11.94 ms .. 12.99 ms)+std dev 1.344 ms (995.0 μs .. 1.928 ms)+variance introduced by outliers: 56% (severely inflated)++benchmarking main/ListTr 500/right right+time 18.27 ms (17.13 ms .. 19.35 ms)+ 0.986 R² (0.975 R² .. 0.998 R²)+mean 18.14 ms (17.70 ms .. 18.98 ms)+std dev 1.466 ms (866.9 μs .. 2.203 ms)+variance introduced by outliers: 35% (moderately inflated)+```
free-category.cabal view
@@ -1,5 +1,5 @@ name: free-category-version: 0.0.3.0+version: 0.0.4.0 synopsis: Free category description: Free categories category: Algebra, Control, Monads, Category@@ -15,7 +15,10 @@ extra-source-files: ChangeLog.md README.md-tested-with: GHC==8.0.2, GHC==8.2.2, GHC==8.4.4, GHC==8.6.5+ bench/report-O0.md+ bench/report-O1.md+ bench/report-O2.md+tested-with: GHC==8.0.2, GHC==8.2.2, GHC==8.4.4, GHC==8.6.5, GHC==8.8.1 source-repository head type: git@@ -26,18 +29,59 @@ Control.Arrow.Free Control.Category.Free Control.Category.Free.Internal- Control.Category.FreeEff+ Control.Category.FreeEffect other-modules: Paths_free_category hs-source-dirs: src build-depends: base >= 4.9 && <5- , free-algebras >= 0.0.7.0+ , free-algebras >= 0.0.8.0 ghc-options: -Wall -fwarn-incomplete-record-updates -fwarn-incomplete-uni-patterns -fwarn-redundant-constraints -fwarn-deprecations+ default-language: Haskell2010++test-suite test-cats+ type:+ exitcode-stdio-1.0+ hs-source-dirs:+ test+ main-is:+ Main.hs+ other-modules:+ Test.Cat+ Test.Queue+ build-depends:+ base+ , QuickCheck+ , tasty-quickcheck+ , tasty+ , free-algebras++ , free-category+ ghc-options:+ -Wall+ -fwarn-incomplete-record-updates+ -fwarn-incomplete-uni-patterns+ -fno-ignore-asserts+ -fwarn-deprecations+ default-language: Haskell2010++benchmark bench-cats+ hs-source-dirs:+ bench+ main-is:+ Main.hs+ type:+ exitcode-stdio-1.0+ build-depends:+ base+ , free-category+ , criterion+ ghc-options:+ -rtsopts default-language: Haskell2010
src/Control/Arrow/Free.hs view
@@ -41,7 +41,7 @@ ( AlgebraType0 , AlgebraType , FreeAlgebra2 (..)- , proof+ , Proof (..) , wrapFree2 , foldFree2 , hoistFree2@@ -63,7 +63,7 @@ mapArr :: f b c -> Arr f a b -> Arr f a c-mapArr bc ac = Cons bc emptyQ . ac+mapArr bc ac = Cons bc nilQ . ac foldArr :: forall f arr a b. Arrow arr@@ -71,7 +71,7 @@ -> Arr f a b -> arr a b foldArr _ Id = id-foldArr fun (Cons bc ab) = fun bc . foldQ (foldNatFree2 fun) ab+foldArr fun (Cons bc ab) = fun bc . foldNatQ (foldNatFree2 fun) ab foldArr fun (Arr f g) = arr f . foldNatFree2 fun g foldArr fun (Prod f g) = foldNatFree2 fun f &&& foldNatFree2 fun g @@ -79,7 +79,7 @@ id = Id Id . f = f f . Id = f- (Cons f g) . h = Cons f (g `snoc` h)+ (Cons f g) . h = Cons f (g `snocQ` h) (Arr f g) . h = Arr f (g . h) (Prod f g) . h = Prod (f . h) (g . h) @@ -103,14 +103,14 @@ type instance AlgebraType Arr c = Arrow c instance FreeAlgebra2 Arr where- liftFree2 = \fab -> Cons fab emptyQ+ liftFree2 = \fab -> Cons fab nilQ {-# INLINE liftFree2 #-} foldNatFree2 = foldArr {-# INLINE foldNatFree2 #-} - codom2 = proof- forget2 = proof+ codom2 = Proof+ forget2 = Proof -- -- Free arrows using CSP style@@ -166,5 +166,5 @@ foldNatFree2 fun (A f) = f fun {-# INLINE foldNatFree2 #-} - codom2 = proof- forget2 = proof+ codom2 = Proof+ forget2 = Proof
src/Control/Category/Free.hs view
@@ -1,13 +1,19 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ViewPatterns #-}+#if __GLASGOW_HASKELL__ >= 806+{-# LANGUAGE QuantifiedConstraints #-}+#endif {-# OPTIONS_HADDOCK show-extensions #-} @@ -20,23 +26,43 @@ #endif module Control.Category.Free- ( -- * Free category- Cat (Id)- , arrCat- , mapCat- , foldCat+ ( -- * Real time Queue+ Queue (ConsQ, NilQ)+ , consQ+ , snocQ+ , unconsQ+ , liftQ+ , foldNatQ+ , foldrQ+ , foldlQ+ , zipWithQ++ -- * Type alligned list+ , ListTr (..)+ , liftL+ , foldNatL+ , foldlL+ , foldrL+ , zipWithL+ -- * Free category (CPS style) , C (..)+ , liftC+ , consC+ , foldNatC , toC , fromC- -- * Oposite category++ -- * Opposite category , Op (..)+ , hoistOp -- * Free interface re-exports , FreeAlgebra2 (..) , wrapFree2 , foldFree2 , hoistFree2+ , hoistFreeH2 , joinFree2 , bindFree2 )@@ -45,17 +71,17 @@ import Prelude hiding (id, concat, (.)) import Control.Category (Category (..)) import Control.Algebra.Free2- ( AlgebraType0- , AlgebraType- , FreeAlgebra2 (..)- , proof- , wrapFree2- , foldFree2- , hoistFree2- , hoistFreeH2- , joinFree2- , bindFree2- )+ ( AlgebraType0+ , AlgebraType+ , FreeAlgebra2 (..)+ , Proof (..)+ , wrapFree2+ , foldFree2+ , hoistFree2+ , hoistFreeH2+ , joinFree2+ , bindFree2+ ) import Control.Arrow (Arrow (..), ArrowZero (..), ArrowChoice (..)) #if __GLASGOW_HASKELL__ < 804 import Data.Monoid (Monoid (..))@@ -63,106 +89,9 @@ #endif import Control.Category.Free.Internal------ Free categories based on real time queues; Ideas after E.Kmett's guanxi--- project.--- --- | Efficient encoding of a category for which morphism composition has--- @O\(1\)@ complexity and fold is linear in the number of transitions.--- -data Cat (f :: k -> k -> *) a b where- Id :: Cat f a a - Cat :: forall f a b c.- f b c- -> Queue (Cat f) a b- -> Cat f a c --- | Smart constructor for embeding spanning transitions into 'Cat', the same--- as @'liftFree2' \@'Cat'@. It is like 'arr' for 'Arrows'. ---arrCat :: forall (f :: k -> k -> *) a b.- f a b- -> Cat f a b-arrCat fab = Cat fab emptyQ---- | Smart constructor 'mapCat' for morphisms of @'Cat' f@ category.----mapCat :: forall (f :: k -> k -> *) a b c.- f b c- -> Cat f a b- -> Cat f a c-mapCat fbc cab = arrCat fbc . cab---- | Right fold of 'Cat' into a category, the same as @'foldNatFree2' \@'Cat'@.------ /complexity/: @O\(n\) where @n@ is number of transition embedded in 'Cat'.-foldCat :: forall f c a b.- Category c- => (forall x y. f x y -> c x y)- -> Cat f a b- -> c a b-foldCat _nat Id = id-foldCat nat (Cat tr queue) =- case queue of- NilQ -> nat tr- ConsQ Id queue' -> nat tr . foldQ (foldCat nat) queue'- ConsQ c queue' -> nat tr . foldCat nat c . foldQ (foldCat nat) queue'---- TODO: implement foldl; it might require different representation. Function--- composition is applied from right to left, so it should be more efficient.---- | /complexity/ of composition @('.')@: @O\(1\)@ (worst case)-instance Category (Cat f) where- id = Id-- Id . f = f- f . Id = f- Cat f q . h = Cat f (q `snoc` h)--type instance AlgebraType0 Cat f = ()-type instance AlgebraType Cat c = Category c---- | /complexity/ of 'foldNatFree2': @O\(n\)@ where @n@ is number of--- transitions embeded in 'Cat'.----instance FreeAlgebra2 Cat where- liftFree2 = arrCat- {-# INLINE liftFree2 #-}-- foldNatFree2 = foldCat- {-# INLINE foldNatFree2 #-}-- codom2 = proof- forget2 = proof--instance Arrow f => Arrow (Cat f) where- arr = arrCat . arr- Cat tr queue *** Cat tr' queue' = Cat (tr *** tr') (zipWithQ (***) queue queue')- Cat tr queue *** Id = Cat (tr *** arr id) (zipWithQ (***) queue NilQ)- Id *** Cat tr' queue' = Cat (arr id *** tr') (zipWithQ (***) NilQ queue')- Id *** Id = Cat (arr id *** arr id) NilQ--instance ArrowZero f => ArrowZero (Cat f) where- zeroArrow = arrCat zeroArrow--instance ArrowChoice f => ArrowChoice (Cat f) where- Cat fxb cax +++ Cat fyb cay- = Cat (fxb +++ fyb) (zipWithQ (+++) cax cay)- Cat fxb cax +++ Id = Cat (fxb +++ arr id) (zipWithQ (+++) cax NilQ)- Id +++ (Cat fxb cax) = Cat (arr id +++ fxb) (zipWithQ (+++) NilQ cax)- Id +++ Id = Id--instance Semigroup (Cat f o o) where- f <> g = f . g--instance Monoid (Cat f o o) where- mempty = Id-#if __GLASGOW_HASKELL__ < 804- mappend = (<>)-#endif---- -- CPS style free categories -- @@ -170,56 +99,115 @@ -- CPS style encoded free category; one can use @'FreeAlgebra2'@ class -- instance: ----- prop> liftFree2 @C :: f a b -> C f a b--- prop> foldNatFree2 @C :: Category d => (forall x y. f x y -> d x y) -> C f a b -> d a b+-- > liftFree2 @C :: f a b -> C f a b+-- > foldNatFree2 @C :: Category d+-- > => (forall x y. f x y -> d x y)+-- > -> C f a b -> d a b+-- newtype C f a b = C { runC :: forall r. Category r => (forall x y. f x y -> r x y) -> r a b } -instance Category (C f) where- id = C (const id)- C bc . C ab = C $ \k -> bc k . ab k+composeC :: C f y z -> C f x y -> C f x z+composeC (C g) (C f) = C $ \k -> g k . f k+{-# INLINE [1] composeC #-} -- |--- Isomorphism from @'Cat'@ to @'C'@, which is a specialisation of+-- Isomorphism from @'ListTr'@ to @'C'@, which is a specialisation of -- @'hoistFreeH2'@. toC :: ListTr f a b -> C f a b toC = hoistFreeH2 {-# INLINE toC #-} -- |--- Inverse of @'fromC'@, which also is a specialisatin of @'hoistFreeH2'@.+-- Inverse of @'fromC'@, which also is a specialisation of @'hoistFreeH2'@. fromC :: C f a b -> ListTr f a b fromC = hoistFreeH2 {-# INLINE fromC #-} +liftC :: forall (f :: k -> k -> *) a b.+ f a b+ -> C f a b+liftC = \f -> C $ \k -> k f+{-# INLINE [1] liftC #-}++consC :: forall (f :: k -> k -> *) a b c.+ f b c+ -> C f a b+ -> C f a c+consC bc ab = liftC bc `composeC` ab+{-# INLINE [1] consC #-}++foldNatC :: forall (f :: k -> k -> *) c a b.+ Category c+ => (forall x y. f x y -> c x y)+ -> C f a b+ -> c a b+foldNatC nat (C f) = f nat+{-# INLINE [1] foldNatC #-}++{-# RULES++"foldNatC/consC"+ forall (f :: f (v :: k) (w :: k))+ (q :: C f (u :: k) (v :: k))+ (nat :: forall (x :: k) (y :: k). f x y -> c x y).+ foldNatC nat (consC f q) = nat f . foldNatC nat q++"foldNatC/liftC"+ forall (nat :: forall (x :: k) (y :: k). f x y -> c x y)+ (g :: f v w)+ (h :: C f u v).+ foldNatC nat (liftC g `composeC` h) = nat g . foldNatC nat h++#-}++instance Category (C f) where+ id = C (const id)+ (.) = composeC++#if __GLASGOW_HASKELL__ >= 806+-- | Show instance via 'ListTr'+--+instance (forall x y. Show (f x y)) => Show (C f a b) where+ show c = show (hoistFreeH2 c :: ListTr f a b)+#else+-- | Blind show instance via 'ListTr'+--+instance Show (C f a b) where+ show c = show (hoistFreeH2 c :: ListTr f a b)+#endif+ type instance AlgebraType0 C f = () type instance AlgebraType C c = Category c instance FreeAlgebra2 C where- liftFree2 = \fab -> C $ \k -> k fab+ liftFree2 = liftC {-# INLINE liftFree2 #-}-- foldNatFree2 fun (C f) = f fun+ foldNatFree2 = foldNatC {-# INLINE foldNatFree2 #-} - codom2 = proof- forget2 = proof+ codom2 = Proof+ forget2 = Proof instance Arrow f => Arrow (C f) where arr ab = C $ \k -> k (arr ab)+ {-# INLINE arr #-}+ C c1 *** C c2 = C $ \k -> k (c1 id *** c2 id)+ {-# INLINE (***) #-} instance ArrowZero f => ArrowZero (C f) where zeroArrow = C $ \k -> k zeroArrow instance ArrowChoice f => ArrowChoice (C f) where C c1 +++ C c2 = C $ \k -> k (c1 id +++ c2 id)+ {-# INLINE (+++) #-} instance Semigroup (C f o o) where- f <> g = f . g+ f <> g = f `composeC` g instance Monoid (C f o o) where mempty = id
src/Control/Category/Free/Internal.hs view
@@ -1,16 +1,21 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ViewPatterns #-} +#if __GLASGOW_HASKELL__ >= 806+{-# LANGUAGE QuantifiedConstraints #-}+#endif+ {-# OPTIONS_HADDOCK show-extensions #-} #if __GLASGOW_HASKELL__ <= 802--- ghc802 does not infer that 'cons' is used when using a bidirectional+-- ghc802 does not infer that 'consQ' is used when using a bidirectional -- pattern {-# OPTIONS_GHC -Wno-unused-top-binds #-} -- the 'complete' pragma was introduced in ghc804@@ -23,13 +28,27 @@ -- module Control.Category.Free.Internal ( Op (..)+ , hoistOp+ , ListTr (..)+ , liftL+ , foldNatL+ , lengthListTr+ , foldrL+ , foldlL+ , zipWithL+ , Queue (NilQ, ConsQ)- , emptyQ- , cons- , uncons- , snoc- , foldQ+ , liftQ+ , nilQ+ , consQ+ , ViewL (..)+ , unconsQ+ , snocQ+ , foldNatQ+ , foldrQ+ , foldlQ+ , hoistQ , zipWithQ ) where @@ -45,14 +64,26 @@ import Control.Algebra.Free2 ( AlgebraType0 , AlgebraType , FreeAlgebra2 (..)- , proof+ , Proof (..) ) -- | Oposite categoy in which arrows from @a@ to @b@ are represented by arrows -- from @b@ to @a@ in the original category. -- newtype Op (f :: k -> k -> *) (a :: k) (b :: k) = Op { runOp :: f b a }+ deriving Show +-- | 'Op' is an endo-functor of the category of categories.+--+hoistOp :: forall (f :: k -> k -> *)+ (g :: k -> k -> *)+ a b.+ (forall x y. f x y -> g x y)+ -> Op f a b+ -> Op g a b+hoistOp nat (Op ba) = Op (nat ba)+{-# INLINE hoistOp #-}+ instance Category f => Category (Op f) where id = Op id Op f . Op g = Op (g . f)@@ -66,25 +97,150 @@ mappend = (<>) #endif --- |--- Free category encoded as a recursive data type, in a simlar way as--- @'Control.Monad.Free.Free'@. You can use @'FreeAlgebra2'@ class instance:+ ----- prop> liftFree2 @Cat :: f a b -> Cat f ab--- prop> foldNatFree2 @Cat :: Category d => (forall x y. f x y -> d x y) -> Cat f a b -> d a b+-- Type aligned list 'ListTr' --+++-- | Simple representation of a free category by using type aligned+-- lists. This is not a surprise as free monoids can be represented by+-- lists (up to laziness)+--+-- 'ListTr' has @'FreeAlgebra2'@ class instance:+--+-- > liftFree2 @ListTr :: f a b -> ListTr f ab+-- > foldNatFree2 @ListTr :: Category d+-- > => (forall x y. f x y -> d x y)+-- > -> ListTr f a b+-- > -> d a b+-- -- The same performance concerns that apply to @'Control.Monad.Free.Free'@ -- apply to this encoding of a free category. --+-- Note that even though this is a naive version, it behaves quite well in+-- simple benchmarks and quite stable regardless of the level of optimisations.+-- data ListTr :: (k -> k -> *) -> k -> k -> * where NilTr :: ListTr f a a ConsTr :: f b c -> ListTr f a b -> ListTr f a c +lengthListTr :: ListTr f a b -> Int+lengthListTr NilTr = 0+lengthListTr (ConsTr _ xs) = 1 + lengthListTr xs++composeL :: forall (f :: k -> k -> *) x y z.+ ListTr f y z+ -> ListTr f x y+ -> ListTr f x z+composeL (ConsTr x xs) ys = ConsTr x (xs . ys)+composeL NilTr ys = ys+{-# INLINE [1] composeL #-}++liftL :: forall (f :: k -> k -> *) x y.+ f x y -> ListTr f x y+liftL f = ConsTr f NilTr+{-# INLINE [1] liftL #-}++foldNatL :: forall (f :: k -> k -> *) c a b.+ Category c+ => (forall x y. f x y -> c x y)+ -> ListTr f a b+ -> c a b+foldNatL _ NilTr = id+foldNatL fun (ConsTr bc ab) = fun bc . foldNatFree2 fun ab+{-# INLINE [1] foldNatL #-}++{-# RULES++"foldNatL/ConsTr"+ forall (f :: f (v :: k) (w :: k))+ (q :: ListTr f (u :: k) (v :: k))+ (nat :: forall (x :: k) (y :: k). f x y -> c x y).+ foldNatL nat (ConsTr f q) = nat f . foldNatL nat q++"foldNatL/NilTr" forall (nat :: forall (x :: k) (y :: k). f x y -> c x y).+ foldNatL nat NilTr = id++"foldNatL/liftL"+ forall (nat :: forall (x :: k) (y :: k). f x y -> c x y)+ (g :: f v w)+ (h :: ListTr f u v).+ foldNatL nat (liftL g `composeL` h) = nat g . foldNatL nat h++#-}++-- | 'foldr' of a 'ListTr'+--+foldrL :: forall (f :: k -> k -> *) c a b d.+ (forall x y z. f y z -> c x y -> c x z)+ -> c a b+ -> ListTr f b d+ -> c a d+foldrL _nat ab NilTr = ab+foldrL nat ab (ConsTr xd bx) = nat xd (foldrL nat ab bx)+{-# INLINE [1] foldrL #-}++-- | 'foldl' of a 'ListTr'+--+-- TODO: make it strict, like 'foldl''.+--+foldlL :: forall (f :: k -> k -> *) c a b d.+ (forall x y z. c y z -> f x y -> c x z)+ -> c b d+ -> ListTr f a b+ -> c a d+foldlL _nat bd NilTr = bd+foldlL nat bd (ConsTr xb ax) = foldlL nat (nat bd xb) ax++zipWithL :: forall f g a b a' b'.+ Category f+ => (forall x y x' y'. f x y -> f x' y' -> f (g x x') (g y y'))+ -> ListTr f a b+ -> ListTr f a' b'+ -> ListTr f (g a a') (g b b')+zipWithL fn queueA queueB = case (queueA, queueB) of+ (NilTr, NilTr) -> NilTr+ (NilTr, ConsTr trB' queueB') -> ConsTr (id `fn` trB') (zipWithL fn NilTr queueB')+ (ConsTr trA' queueA', NilTr) -> ConsTr (trA' `fn` id) (zipWithL fn queueA' NilTr)+ (ConsTr trA' queueA', ConsTr trB' queueB')+ -> ConsTr (trA' `fn` trB') (zipWithL fn queueA' queueB')++#if __GLASGOW_HASKELL__ >= 806+instance (forall (x :: k) (y :: k). Show (f x y)) => Show (ListTr f a b) where+ show NilTr = "NilTr"+ show (ConsTr x xs) = "ConsTr " ++ show x ++ " " ++ show xs+#else+instance Show (ListTr f a b) where+ show NilTr = "NilTr"+ show (ConsTr _ xs) = "ConsTr _ " ++ show xs+#endif+ instance Category (ListTr f) where- id = NilTr- NilTr . ys = ys- (ConsTr x xs) . ys = ConsTr x (xs . ys)+ id = NilTr+ (.) = composeL +type instance AlgebraType0 ListTr f = ()+type instance AlgebraType ListTr c = Category c++instance FreeAlgebra2 ListTr where+ liftFree2 = liftL+ {-# INLINE liftFree2 #-}+ foldNatFree2 = foldNatL+ {-# INLINE foldNatFree2 #-}++ codom2 = Proof+ forget2 = Proof++instance Semigroup (ListTr f o o) where+ f <> g = g . f++instance Monoid (ListTr f o o) where+ mempty = NilTr+#if __GLASGOW_HASKELL__ < 804+ mappend = (<>)+#endif+ instance Arrow f => Arrow (ListTr f) where arr ab = arr ab `ConsTr` NilTr @@ -104,99 +260,163 @@ NilTr +++ (ConsTr fxb cax) = (arr id +++ fxb) `ConsTr` (NilTr +++ cax) NilTr +++ NilTr = NilTr -instance Semigroup (ListTr f o o) where- f <> g = g . f -instance Monoid (ListTr f o o) where- mempty = NilTr-#if __GLASGOW_HASKELL__ < 804- mappend = (<>)-#endif--type instance AlgebraType0 ListTr f = ()-type instance AlgebraType ListTr c = Category c--instance FreeAlgebra2 ListTr where- liftFree2 = \fab -> ConsTr fab NilTr- {-# INLINE liftFree2 #-}-- foldNatFree2 _ NilTr = id- foldNatFree2 fun (ConsTr bc ab) = fun bc . foldNatFree2 fun ab- {-# INLINE foldNatFree2 #-}-- codom2 = proof- forget2 = proof+--+-- Type aligned real time 'Queue'+-- -- | Type alligned real time queues; Based on `Purely Functinal Data Structures`--- C.Okasaki.+-- C.Okasaki. This the most reliably behaved implementation of free categories+-- in this package. ----- Upper bounds of `cons`, `snoc`, `uncons` are @O\(1\)@ (worst case).+-- Upper bounds of `consQ`, `snocQ`, `unconsQ` are @O\(1\)@ (worst case). ----- Invariant: sum of lengths of two last least is equal the length of the first--- one.+-- Internal invariant: sum of lengths of two last least is equal the length of+-- the first one. -- data Queue (f :: k -> k -> *) (a :: k) (b :: k) where Queue :: forall f a c b x.- !(ListTr f b c)+ ListTr f b c -> !(ListTr (Op f) b a)- -> !(ListTr f b x)+ -> ListTr f b x -> Queue f a c -emptyQ :: Queue (f :: k -> k -> *) a a-emptyQ = Queue NilTr NilTr NilTr+pattern ConsQ :: f b c -> Queue f a b -> Queue f a c+pattern ConsQ a as <- (unconsQ -> a :< as) where+ ConsQ = consQ -cons :: forall (f :: k -> k -> *) a b c.- f b c- -> Queue f a b- -> Queue f a c-cons fbc (Queue f r s) = Queue (ConsTr fbc f) r (ConsTr undefined s)+pattern NilQ :: () => a ~ b => Queue f a b+pattern NilQ <- (unconsQ -> EmptyL) where+ NilQ = nilQ +#if __GLASGOW_HASKELL__ > 802+{-# complete NilQ, ConsQ #-}+#endif++composeQ :: forall (f :: k -> k -> *) x y z.+ Queue f y z+ -> Queue f x y+ -> Queue f x z+composeQ (ConsQ f q1) q2 = ConsQ f (q1 . q2)+composeQ NilQ q2 = q2+{-# INLINE [1] composeQ #-}++nilQ :: Queue (f :: k -> k -> *) a a+nilQ = Queue NilTr NilTr NilTr+{-# INLINE [1] nilQ #-}++consQ :: forall (f :: k -> k -> *) a b c.+ f b c+ -> Queue f a b+ -> Queue f a c+consQ bc (Queue f r s) = Queue (ConsTr bc f) r (ConsTr undefined s)+{-# INLINE [1] consQ #-}+ data ViewL f a b where EmptyL :: ViewL f a a (:<) :: f b c -> Queue f a b -> ViewL f a c -- | 'uncons' a 'Queue', complexity: @O\(1\)@ ---uncons :: Queue f a b- -> ViewL f a b-uncons (Queue NilTr NilTr _) = EmptyL-uncons (Queue (ConsTr tr f) r (ConsTr _ s)) = tr :< exec f r s-uncons _ = error "Queue.uncons: invariant violation"+unconsQ :: Queue f a b+ -> ViewL f a b+unconsQ (Queue NilTr NilTr _) = EmptyL+unconsQ (Queue (ConsTr tr f) r s) = tr :< exec f r s+unconsQ _ = error "Queue.uncons: invariant violation"+{-# INLINE unconsQ #-} -snoc :: forall (f :: k -> k -> *) a b c.- Queue f b c- -> f a b- -> Queue f a c-snoc (Queue f r s) g = exec f (ConsTr (Op g) r) s+snocQ :: forall (f :: k -> k -> *) a b c.+ Queue f b c+ -> f a b+ -> Queue f a c+snocQ (Queue f r s) g = exec f (ConsTr (Op g) r) s+{-# INLINE snocQ #-} -pattern ConsQ :: f b c -> Queue f a b -> Queue f a c-pattern ConsQ a as <- (uncons -> a :< as) where- ConsQ = cons+-- | 'foldr' of a 'Queue'+--+foldrQ :: forall (f :: k -> k -> *) c a b d.+ (forall x y z. f y z -> c x y -> c x z)+ -> c a b+ -> Queue f b d+ -> c a d+foldrQ _nat ab NilQ = ab+foldrQ nat ab (ConsQ xd bx) = nat xd (foldrQ nat ab bx)+{-# INLINE [1] foldrQ #-} -pattern NilQ :: () => a ~ b => Queue f a b-pattern NilQ <- (uncons -> EmptyL) where- NilQ = emptyQ+{-# RULES -#if __GLASGOW_HASKELL__ > 802-{-# complete NilQ, ConsQ #-}-#endif+"foldrQ/consQ/nilQ"+ foldrQ consQ nilQ = id --- | Efficient fold of a queue into a category.+"foldrQ/single"+ forall (nat :: forall (x :: k) (y :: k) (z :: k). f y z -> c x y -> c x z)+ (t :: f (v :: k) (w :: k))+ (nil :: c (u :: k) (v :: k)).+ foldrQ nat nil (consQ t nilQ) = nat t nil++"foldrQ/nilQ"+ forall (nat :: forall (x :: k) (y :: k) (z :: k). f y z -> c x y -> c x z)+ (nil :: c (u :: k) (v :: k)).+ foldrQ nat nil nilQ = nil++"foldrQ/consQ"+ forall (f :: Queue f (x :: k) (y :: k))+ (g :: Queue f (y :: k) (z :: k)).+ foldrQ consQ f g = g . f++#-}++liftQ :: forall (f :: k -> k -> *) a b.+ f a b -> Queue f a b+liftQ = \fab -> ConsQ fab NilQ+{-# INLINE [1] liftQ #-}++-- | Efficient fold of a queue into a category, analogous to 'foldM'. -- -- /complexity/ @O\(n\)@ ---foldQ :: forall (f :: k -> k -> *) c a b.- Category c- => (forall x y. f x y -> c x y)- -> Queue f a b- -> c a b-foldQ nat queue = case queue of- NilQ -> id- ConsQ tr queue' -> nat tr . foldQ nat queue'+foldNatQ :: forall (f :: k -> k -> *) c a b.+ Category c+ => (forall x y. f x y -> c x y)+ -> Queue f a b+ -> c a b+foldNatQ nat = foldrQ (\f c -> nat f . c) id+{-# INLINE [1] foldNatQ #-} +{-# RULES++"foldNatQ/consQ" forall (f :: f (v :: k) (w :: k))+ (q :: Queue f (u :: k) (v :: k))+ (nat :: forall (x :: k) (y :: k). f x y -> c x y).+ foldNatQ nat (consQ f q) = nat f . foldNatQ nat q++"foldNatQ/nilQ" forall (nat :: forall (x :: k) (y :: k). f x y -> c x y).+ foldNatQ nat nilQ = id+++"foldNatC/liftQ"+ forall (nat :: forall (x :: k) (y :: k). f x y -> c x y)+ (g :: f v w)+ (h :: Queue f u v).+ foldNatQ nat (liftQ g `composeQ` h) = nat g . foldNatQ nat h++#-}++-- | 'foldl' of a 'Queue'+--+-- TODO: make it strict, like 'foldl''.+--+foldlQ :: forall (f :: k -> k -> *) c a b d.+ (forall x y z. c y z -> f x y -> c x z)+ -> c b d+ -> Queue f a b+ -> c a d+foldlQ _nat bd NilQ = bd+foldlQ nat bd (ConsQ xb ax) = foldlQ nat (nat bd xb) ax+ zipWithQ :: forall f g a b a' b'.- Arrow f+ Category f => (forall x y x' y'. f x y -> f x' y' -> f (g x x') (g y y')) -> Queue f a b -> Queue f a' b'@@ -209,12 +429,112 @@ -> ConsQ (trA' `fn` trB') (zipWithQ fn queueA' queueB') +-- | 'Queue' is an endo-functor on the category of graphs (or category of+-- categories), thus one can hoist the transitions using a natural+-- transformation. This in analogy to @'map' :: (a -> b) -> [a] -> [b]@.+--+hoistQ :: forall (f :: k -> k -> *)+ (g :: k -> k -> *)+ a b.+ (forall x y. f x y -> g x y)+ -> Queue f a b+ -> Queue g a b+hoistQ nat q = case q of+ NilQ -> NilQ+ ConsQ tr q' -> ConsQ (nat tr) (hoistQ nat q')+{-# INLINE [1] hoistQ #-} +{-# RULES++"hoistQ/foldNatQ"+ forall (nat1 :: forall (x :: k) (y :: k). f x y -> g x y)+ (nat :: forall (x :: k) (y :: k). g x y -> h x y)+ (q :: Queue f x y).+ foldNatQ nat (hoistQ nat1 q) = foldNatQ (nat . nat1) q++"hoistQ/hoistQ"+ forall (nat1 :: forall (x :: k) (y :: k). f x y -> g x y)+ (nat :: forall (x :: k) (y :: k). g x y -> h x y)+ (q :: Queue f x y).+ hoistQ nat (hoistQ nat1 q) = hoistQ (nat . nat1) q++#-}++#if __GLASGOW_HASKELL__ >= 806+instance (forall (x :: k) (y :: k). Show (f x y))+ => Show (Queue f a b) where+ show (Queue f r s) =+ "Queue ("+ ++ show f+ ++ ") ("+ ++ show r+ ++ ") "+ ++ show (lengthListTr s)+#else+instance Show (Queue f r s) where+ show (Queue f r s) =+ "Queue "+ ++ show (lengthListTr f)+ ++ " "+ ++ show (lengthListTr r)+ ++ " "+ ++ show (lengthListTr s)+#endif++instance Category (Queue f) where+ id = NilQ+ (.) = composeQ++type instance AlgebraType0 Queue f = ()+type instance AlgebraType Queue c = Category c++instance FreeAlgebra2 Queue where+ liftFree2 = liftQ+ {-# INLINE liftFree2 #-}+ foldNatFree2 = foldNatQ+ {-# INLINE foldNatFree2 #-}++ codom2 = Proof+ forget2 = Proof++instance Semigroup (Queue f o o) where+ f <> g = g `composeQ` f++instance Monoid (Queue f o o) where+ mempty = NilQ+#if __GLASGOW_HASKELL__ < 804+ mappend = (<>)+#endif++instance Arrow f => Arrow (Queue f) where+ arr ab = arr ab `ConsQ` NilQ++ (ConsQ fxb cax) *** (ConsQ fyb cay)+ = (fxb *** fyb) `ConsQ` (cax *** cay)+ (ConsQ fxb cax) *** NilQ = (fxb *** arr id) `ConsQ` (cax *** NilQ)+ NilQ *** (ConsQ fxb cax) = (arr id *** fxb) `ConsQ` (NilQ *** cax)+ NilQ *** NilQ = NilQ++instance ArrowZero f => ArrowZero (Queue f) where+ zeroArrow = zeroArrow `ConsQ` NilQ++instance ArrowChoice f => ArrowChoice (Queue f) where+ (ConsQ fxb cax) +++ (ConsQ fyb cay)+ = (fxb +++ fyb) `ConsQ` (cax +++ cay)+ (ConsQ fxb cax) +++ NilQ = (fxb +++ arr id) `ConsQ` (cax +++ NilQ)+ NilQ +++ (ConsQ fxb cax) = (arr id +++ fxb) `ConsQ` (NilQ +++ cax)+ NilQ +++ NilQ = NilQ++--+-- Internal API+--+ exec :: ListTr f b c -> ListTr (Op f) b a -> ListTr f b x -> Queue f a c exec xs ys (ConsTr _ t) = Queue xs ys t exec xs ys NilTr = Queue xs' NilTr xs' where xs' = rotate xs ys NilTr+{-# INLINABLE exec #-} rotate :: ListTr f c d -> ListTr (Op f) c b -> ListTr f a b -> ListTr f a d rotate NilTr (ConsTr (Op f) NilTr) a = ConsTr f a
− src/Control/Category/FreeEff.hs
@@ -1,89 +0,0 @@-{-# LANGUAGE GADTs #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE TypeFamilies #-}--{-# OPTIONS_HADDOCK show-extensions #-}--module Control.Category.FreeEff- ( EffCategory (..)- , FreeEffCat (..)- , liftCat- , foldNatLift- , liftKleisli- ) where--import Prelude hiding (id, (.))--import Control.Arrow (Kleisli (..))-import Control.Category (Category (..))-import Data.Functor.Identity (Identity (..))--import Control.Category.Free (Cat)-import Control.Algebra.Free2 (FreeAlgebra2 (..))-import Data.Algebra.Free (AlgebraType, AlgebraType0, proof)----- | Categories which can lift monadic actions, i.e. effectful categories.----class Category c => EffCategory c m | c -> m where- lift :: m (c a b) -> c a b--instance Monad m => EffCategory (Kleisli m) m where- lift m = Kleisli (\a -> m >>= \(Kleisli f) -> f a)--instance EffCategory (->) Identity where- lift = runIdentity---- | Category transformer, which adds @'EffCategory'@ instance to the--- underlying base category.----data FreeEffCat :: (* -> *) -> (k -> k -> *) -> k -> k -> * where- Base :: c a b -> FreeEffCat m c a b- Lift :: m (FreeEffCat m c a b) -> FreeEffCat m c a b--instance (Functor m, Category c) => Category (FreeEffCat m c) where- id = Base id- Base f . Base g = Base $ f . g- f . Lift mg = Lift $ (f .) <$> mg- Lift mf . g = Lift $ (. g) <$> mf--instance (Functor m, Category c) => EffCategory (FreeEffCat m c) m where- lift = Lift--type instance AlgebraType0 (FreeEffCat m) c = (Monad m, Category c)-type instance AlgebraType (FreeEffCat m) c = EffCategory c m-instance Monad m => FreeAlgebra2 (FreeEffCat m) where- liftFree2 = Base- foldNatFree2 nat (Base cab) = nat cab- foldNatFree2 nat (Lift mcab) = lift $ foldNatFree2 nat <$> mcab-- codom2 = proof- forget2 = proof---- | Wrap a transition into a free category @'Cat'@ and then in--- @'FreeEffCat'@------ prop> liftCat tr = Base (tr :.: Id)----liftCat :: Monad m => tr a b -> FreeEffCat m (Cat tr) a b-liftCat = liftFree2 . liftFree2---- | Fold @'FreeLifing'@ category based on a free category @'Cat' tr@ using--- a functor @tr x y -> c x y@.----foldNatLift- :: (Monad m, EffCategory c m)- => (forall x y. tr x y -> c x y)- -> FreeEffCat m (Cat tr) a b- -> c a b-foldNatLift nat = foldNatFree2 (foldNatFree2 nat)---- | Functor from @'->'@ category to @'Kleisli' m@. If @m@ is @Identity@ then--- it will respect @'lift'@ i.e. @liftKleisli (lift ar) = lift (liftKleisli <$>--- ar).----liftKleisli :: Applicative m => (a -> b) -> Kleisli m a b-liftKleisli f = Kleisli (pure . f)
+ src/Control/Category/FreeEffect.hs view
@@ -0,0 +1,97 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeFamilies #-}++{-# OPTIONS_HADDOCK show-extensions #-}++module Control.Category.FreeEffect+ ( EffectCategory (..)+ , EffCat (..)+ , liftEffect+ , foldNatEffCat+ , liftKleisli+ ) where++import Prelude hiding (id, (.))++import Control.Arrow (Kleisli (..))+import Control.Category (Category (..))+import Data.Functor.Identity (Identity (..))++import Control.Algebra.Free2 (FreeAlgebra2 (..))+import Data.Algebra.Free (AlgebraType, AlgebraType0, Proof (..))+++-- | Categories which can lift monadic actions, i.e. effectful categories.+--+class Category c => EffectCategory c m | c -> m where+ effect :: m (c a b) -> c a b++instance Monad m => EffectCategory (Kleisli m) m where+ effect m = Kleisli (\a -> m >>= \(Kleisli f) -> f a)++instance EffectCategory (->) Identity where+ effect = runIdentity++-- | Category transformer, which adds @'EffectCategory'@ instance to the+-- underlying base category.+--+data EffCat :: (* -> *) -> (k -> k -> *) -> k -> k -> * where+ Base :: c a b -> EffCat m c a b+ Effect :: m (EffCat m c a b) -> EffCat m c a b++instance (Functor m, Category c) => Category (EffCat m c) where+ id = Base id+ Base f . Base g = Base $ f . g+ f . Effect mg = Effect $ (f .) <$> mg+ Effect mf . g = Effect $ (. g) <$> mf++instance (Functor m, Category c) => EffectCategory (EffCat m c) m where+ effect = Effect++type instance AlgebraType0 (EffCat m) c = (Monad m, Category c)+type instance AlgebraType (EffCat m) c = EffectCategory c m+instance Monad m => FreeAlgebra2 (EffCat m) where+ liftFree2 = Base+ foldNatFree2 nat (Base cab) = nat cab+ foldNatFree2 nat (Effect mcab) = effect $ foldNatFree2 nat <$> mcab++ codom2 = Proof+ forget2 = Proof++-- | Wrap a transition into @'EffCat' cat@ for any free category 'cat' (e.g.+-- 'Cat').+--+liftEffect :: ( Monad m+ , FreeAlgebra2 cat+ , AlgebraType0 cat tr+ , Category (cat tr)+ )+ => tr a b -> EffCat m (cat tr) a b+liftEffect = liftFree2 . liftFree2++-- | Fold @'FreeLifing'@ category based on a free category @'cat' tr@ (e.g.+-- @'Cat' tr@) using a functor @tr x y -> c x y@.+--+foldNatEffCat+ :: ( Monad m+ , FreeAlgebra2 cat+ , AlgebraType cat c+ , AlgebraType0 cat tr+ , Category (cat tr)+ , EffectCategory c m+ )+ => (forall x y. tr x y -> c x y)+ -> EffCat m (cat tr) a b+ -> c a b+foldNatEffCat nat = foldNatFree2 (foldNatFree2 nat)++-- | Functor from @(->)@ category to @'Kleisli' m@. If @m@ is 'Identity' then+-- it will respect 'effect' i.e.+-- @'liftKleisli' ('effect' ar) = 'effect' ('liftKleisli' \<$\> ar)@.+--+liftKleisli :: Applicative m => (a -> b) -> Kleisli m a b+liftKleisli f = Kleisli (pure . f)
+ test/Main.hs view
@@ -0,0 +1,17 @@+module Main (main) where++import Test.Tasty++import qualified Test.Queue+import qualified Test.Cat++main :: IO ()+main = defaultMain tests++tests :: TestTree+tests =+ testGroup "free-categories"+ -- data structures+ [ Test.Queue.tests+ , Test.Cat.tests+ ]
+ test/Test/Cat.hs view
@@ -0,0 +1,410 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE UndecidableInstances #-}+#if __GLASGOW_HASKELL__ >= 806+{-# LANGUAGE QuantifiedConstraints #-}+#endif++{-# OPTIONS_GHC -Wno-orphans #-}++module Test.Cat (tests) where++import Prelude hiding ((.), id)+import Control.Category+import Data.Function (on)+#if __GLASGOW_HASKELL__ < 804+import Data.Monoid (Monoid (..))+import Data.Semigroup (Semigroup (..))+#endif+import Text.Show.Functions ()+import Numeric.Natural (Natural)++import Control.Algebra.Free2+import Control.Category.Free++import Test.QuickCheck+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.QuickCheck (testProperty)++tests :: TestTree+tests =+ testGroup "Control.Category.Free"+ [ testProperty "Queue" prop_Queue+ , testProperty "C" prop_C+ , testGroup "Category laws"+ [ testProperty "ListTr id" prop_id_ListTr+ , testProperty "ListTr associativity" prop_associativity_ListTr+ , testProperty "Queue id" prop_id_Queue+ , testProperty "Queue associativity" prop_associativity_Queue+ , testProperty "C id" prop_id_C+ , testProperty "C associativity" prop_associativity_C+ ]+ , testGroup "foldFree2 and foldMap"+ [ testProperty "foldFree ListTr" prop_foldListTr+ , testProperty "foldFree Queue" prop_foldQueue+ , testProperty "foldFree C" prop_foldC+ ]+ ]+++data Tr a b where+ -- Num transition+ NumTr :: Num a => (a -> a) -> Tr a a+ FromInteger :: Num b => Tr Integer b++ -- Integral transition+ ToInteger :: Integral a => Tr a Integer+++interpretTr :: Tr a b -> a -> b+interpretTr (NumTr f) = f+interpretTr FromInteger = fromInteger+interpretTr ToInteger = toInteger+++instance (Show a, Show b) => Show (Tr a b) where+ show (NumTr f) = "NumTr " ++ show f+ show FromInteger = "FromInteger"+ show ToInteger = "ToInteger"+++data SomeNumTr f a where+ SomeNumTr :: Num a+ => f Tr a a+ -> SomeNumTr f a++instance Show (f Tr a a) => Show (SomeNumTr f a) where+ show (SomeNumTr f) = "SomeNumTr " ++ show f+++data SomeIntegralTr f a where+ SomeIntegralTr :: Integral a+ => f Tr a a+ -> SomeIntegralTr f a++instance Show (f Tr a a) => Show (SomeIntegralTr f a) where+ show (SomeIntegralTr f) = "SomeIntegralTr " ++ show f+++-- A 'fromIntegral' transition in any free category @f@.+fromIntegralTr :: ( Integral a+ , Num b+ , Category (f Tr)+ , AlgebraType0 f Tr+ , FreeAlgebra2 f+ ) => f Tr a b+fromIntegralTr = liftFree2 FromInteger . liftFree2 ToInteger+++data Sing a where+ SInt :: Sing Int+ SInteger :: Sing Integer+ SNatural :: Sing Natural++instance Show (Sing a) where+ show SInt = "SInt"+ show SInteger = "SInteger"+ show SNatural = "SNatural"++data AnySing where+ AnySing :: Eq a => Sing a -> AnySing++instance Eq AnySing where+ AnySing SInt == AnySing SInt = True+ AnySing SInteger == AnySing SInteger = True+ AnySing SNatural == AnySing SNatural = True+ _ == _ = False++instance Show AnySing where+ show (AnySing sing) = show sing++instance Arbitrary AnySing where+ arbitrary = oneof+ [ pure $ AnySing SInt+ , pure $ AnySing SInteger+ , pure $ AnySing SNatural+ ]+++instance Arbitrary Natural where+ arbitrary =+ fromIntegral . getPositive <$> (arbitrary :: Gen (Positive Integer))++instance CoArbitrary Natural where+ coarbitrary a = variant (fromIntegral a :: Int)++data AnyListTr b where+ AnyListTr :: Eq c => ListTr Tr b c -> Sing c -> AnyListTr b+++genNextTr :: Sing b+ -> Gen (AnyListTr b)+genNextTr b = do+ AnySing c <- arbitrary+ case (b, c) of+ (SInt, SInt) ->+ (\f -> AnyListTr (ConsTr (NumTr f) NilTr) c) <$> arbitrary+ (SInteger, SInteger) ->+ (\f -> AnyListTr (ConsTr (NumTr f) NilTr) c) <$> arbitrary+ (SNatural, SNatural) ->+ (\f -> AnyListTr (ConsTr (NumTr f) NilTr) c) <$> arbitrary++ (SInt, SInteger) ->+ pure $ AnyListTr fromIntegralTr c+ (SInt, SNatural) ->+ pure $ AnyListTr (fromIntegralTr . liftFree2 (NumTr abs)) c+ (SInteger, SInt) ->+ pure $ AnyListTr fromIntegralTr c+ (SNatural, SInt) ->+ pure $ AnyListTr fromIntegralTr c+ (SNatural, SInteger) ->+ pure $ AnyListTr fromIntegralTr c+ (SInteger, SNatural) ->+ pure $ AnyListTr (fromIntegralTr . liftFree2 (NumTr abs)) c+++data ArbListTr where+ ArbListTr :: Eq b => ListTr Tr a b -> Sing a -> Sing b -> ArbListTr++#if __GLASGOW_HASKELL__ >= 806+instance (forall x y. Show (Tr x y)) => Show ArbListTr where+ show (ArbListTr listTr a b) =+ "ArbListTr "+ ++ show a+ ++ " -> "+ ++ show b+ ++ " "+ ++ show listTr+#else+instance Show ArbListTr where+ show (ArbListTr _listTr a b) =+ "ArbListTr "+ ++ show a+ ++ " -> "+ ++ show b+#endif++instance Arbitrary ArbListTr where+ arbitrary = sized $ \n -> do+ k <- choose (0, n)+ AnySing a <- arbitrary+ go k a (AnyListTr NilTr a)+ where+ go 0 a (AnyListTr ab b) = pure $ ArbListTr ab a b+ go n a (AnyListTr ab b) = do+ AnyListTr bc c <- genNextTr b+ -- (.) can be used as (++) for ListTr+ go (n - 1) a $ AnyListTr (bc . ab) c+++--+-- test 'Cat' and 'C' treating 'ListTr' as a model to compare to.+--+prop_Queue, prop_C+ :: Blind ArbListTr -> Bool+++prop_Queue (Blind (ArbListTr listTr SInt _)) =+ foldNatFree2 interpretTr (hoistFreeH2 @_ @Queue listTr) 0+ ==+ foldNatFree2 interpretTr listTr 0+prop_Queue (Blind (ArbListTr listTr SInteger _)) =+ foldNatFree2 interpretTr (hoistFreeH2 @_ @Queue listTr) 0+ ==+ foldNatFree2 interpretTr listTr 0+prop_Queue (Blind (ArbListTr listTr SNatural _)) =+ foldNatFree2 interpretTr (hoistFreeH2 @_ @Queue listTr) 0+ ==+ foldNatFree2 interpretTr listTr 0+++prop_C (Blind (ArbListTr listTr SInt _)) =+ foldNatFree2 interpretTr (hoistFreeH2 @_ @C listTr) 0+ ==+ foldNatFree2 interpretTr listTr 0+prop_C (Blind (ArbListTr listTr SInteger _)) =+ foldNatFree2 interpretTr (hoistFreeH2 @_ @C listTr) 0+ ==+ foldNatFree2 interpretTr listTr 0+prop_C (Blind (ArbListTr listTr SNatural _)) =+ foldNatFree2 interpretTr (hoistFreeH2 @_ @C listTr) 0+ ==+ foldNatFree2 interpretTr listTr 0++--+-- Test Category Laws+-- @+-- f . id == f == id . f+-- f . g . h == (f . g) . h+-- @+--++prop_id :: Category c+ => (c a b -> c a b -> Bool)+ -> c a b+ -> Bool+prop_id eqCat f = eqCat (f . id) f && eqCat (id . f) f++prop_associativity :: Category c+ => (c x w -> c x w -> Bool)+ -> c z w -> c y z -> c x y+ -> Bool+prop_associativity eqCat f g h =+ (f . g . h) `eqCat` ((f . g) . h)+++-- | Integers form commutative monoid, and thus a category (a groupoid to be+-- precise) with a single object.+--+data IntCat (a :: ()) (b :: ()) where+ IntCat :: Int -> IntCat a a++instance Show (IntCat a b) where+ show (IntCat i) = "IntCat " ++ show i++instance Eq (IntCat a b) where+ IntCat i == IntCat j = i == j++instance Category IntCat where+ id = IntCat 0+ IntCat a . IntCat b = IntCat (a + b)++instance Semigroup (IntCat '() '()) where+ IntCat a <> IntCat b = IntCat (a + b)++instance Monoid (IntCat '() '()) where+ mempty = IntCat 0+#if __GLASGOW_HASKELL__ < 804+ mappend = (<>)+#endif++instance Arbitrary (IntCat '() '()) where+ arbitrary = IntCat <$> arbitrary++fromList :: forall (a :: k) m f.+ ( FreeAlgebra2 m+ , AlgebraType0 m f+ , Category (m f)+ ) => [f a a] -> m f a a+fromList [] = id+fromList (f : fs) = liftFree2 f . fromList fs++toList :: ( FreeAlgebra2 m+ , AlgebraType0 m IntCat+ , AlgebraType m (ListTr IntCat)+ )+ => m IntCat '() '()+ -> [IntCat '() '()]+toList c = go (hoistFreeH2 c)+ where+ go :: ListTr IntCat '() '() -> [IntCat '() '()]+ go NilTr = []+ go (ConsTr tr@IntCat{} xs) = tr : go xs++--+-- 'C' category laws+--++newtype ArbIntC = ArbIntC (C IntCat '() '())++instance Show ArbIntC where+ show (ArbIntC c) = show c++instance Arbitrary ArbIntC where+ arbitrary = ArbIntC . fromList <$> arbitrary+ shrink (ArbIntC c) =+ map (ArbIntC . fromList)+ $ shrinkList (const [])+ $ toList c++prop_id_C :: ArbIntC -> Bool+prop_id_C (ArbIntC f) =+ prop_id (on (==) toList) f++prop_associativity_C+ :: ArbIntC -> ArbIntC -> ArbIntC+ -> Bool+prop_associativity_C (ArbIntC f0)+ (ArbIntC f1)+ (ArbIntC f2) =+ prop_associativity (on (==) toList) f0 f1 f2++--+-- 'Queue' category laws+--++newtype ArbIntQueue = ArbIntQueue (Queue IntCat '() '())++instance Show ArbIntQueue where+ show (ArbIntQueue f) = show (toList f)++instance Arbitrary ArbIntQueue where+ arbitrary = ArbIntQueue . fromList <$> arbitrary+ shrink (ArbIntQueue c) =+ map (ArbIntQueue . fromList)+ $ shrinkList (const [])+ $ toList c++prop_id_Queue :: ArbIntQueue -> Bool+prop_id_Queue (ArbIntQueue f) =+ prop_id (on (==) toList) f++prop_associativity_Queue+ :: ArbIntQueue -> ArbIntQueue -> ArbIntQueue+ -> Bool+prop_associativity_Queue (ArbIntQueue f0)+ (ArbIntQueue f1)+ (ArbIntQueue f2) =+ prop_associativity (on (==) toList) f0 f1 f2++--+-- 'ListTr' category laws+--++newtype ArbIntListTr = ArbIntListTr (ListTr IntCat '() '())++instance Show ArbIntListTr where+ show (ArbIntListTr f) = show (toList f)++instance Arbitrary ArbIntListTr where+ arbitrary = ArbIntListTr . fromList <$> arbitrary+ shrink (ArbIntListTr c) =+ map (ArbIntListTr . fromList)+ $ shrinkList (const [])+ $ toList c++prop_id_ListTr :: ArbIntListTr -> Bool+prop_id_ListTr (ArbIntListTr f) =+ prop_id (on (==) toList) f++prop_associativity_ListTr+ :: ArbIntListTr -> ArbIntListTr -> ArbIntListTr+ -> Bool+prop_associativity_ListTr (ArbIntListTr f0)+ (ArbIntListTr f1)+ (ArbIntListTr f2) =+ prop_associativity (on (==) toList) f0 f1 f2+++--+-- Compatibility between 'foldFree2' and 'foldMap' for 'IntCat'+--++prop_foldListTr :: ArbIntListTr -> Bool+prop_foldListTr (ArbIntListTr f)+ = foldFree2 f == foldMap id (toList f)++prop_foldQueue :: ArbIntQueue -> Bool+prop_foldQueue (ArbIntQueue f)+ = foldFree2 f == foldMap id (toList f)++prop_foldC :: (Blind ArbIntC) -> Bool+prop_foldC (Blind (ArbIntC f))+ = foldFree2 f == foldMap id (toList f)
+ test/Test/Queue.hs view
@@ -0,0 +1,113 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++module Test.Queue (tests) where++import Prelude hiding ((.), id)+import Text.Show.Functions ()++import Control.Category.Free.Internal++import Test.QuickCheck+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.QuickCheck (testProperty)++tests :: TestTree+tests =+ testGroup "Queue"+ [ testProperty "consQ" prop_consQ+ , testProperty "unconsQ" prop_unconsQ+ , testProperty "snocQ" prop_snocQ+ , testProperty "foldrQ" (prop_foldr @Int)+ , testProperty "foldrQ" (prop_foldl @Int)+ ]++data K = K++data Tr (a :: K) (b :: K) where+ A :: Int -> Tr 'K 'K++instance Eq (Tr 'K 'K) where+ A i == A j = i == j++instance Show (Tr a b) where+ show (A i) = "A " ++ show i++instance Arbitrary (Tr 'K 'K) where+ arbitrary = A <$> arbitrary+++toList :: Queue Tr 'K 'K -> [Tr 'K 'K]+toList q = case q of+ ConsQ a@A{} as -> a : toList as+ _ -> []+++fromList :: [Tr 'K 'K] -> Queue Tr 'K 'K+fromList [] = NilQ+fromList (a : as) = ConsQ a (fromList as)+++instance Arbitrary (Queue Tr 'K 'K) where+ arbitrary = fromList <$> arbitrary+ shrink q = map fromList $ shrinkList (const []) (toList q)+++prop_unconsQ :: Queue Tr 'K 'K -> Bool+prop_unconsQ q = case (q, toList q) of+ (ConsQ a@A{} _, a' : _) -> a == a'+ (NilQ, []) -> True+ _ -> False+++prop_consQ :: Tr 'K 'K -> Queue Tr 'K 'K -> Bool+prop_consQ a@A{} q = case consQ a q of+ ConsQ a'@A{} _ -> a' == a'+ _ -> False+++prop_snocQ :: Tr 'K 'K -> Queue Tr 'K 'K -> Bool+prop_snocQ a@A{} q = last (toList (q `snocQ` a)) == a+++data TrA a (x :: K) (y :: K) where+ TrA :: a -> TrA a 'K 'K++instance Show a => Show (TrA a 'K 'K) where+ show (TrA a) = "TrA " ++ show a++instance Eq a => Eq (TrA a k k) where+ TrA a == TrA b = a == b++instance Arbitrary a => Arbitrary (TrA a 'K 'K) where+ arbitrary = TrA <$> arbitrary+ shrink (TrA a) = map TrA (shrink a)+++prop_foldr :: forall a.+ Eq a+ => (Int -> a -> a)+ -> TrA a 'K 'K+ -> Queue Tr 'K 'K+ -> Bool+prop_foldr f a q = foldrQ g a q == foldr g a (toList q)+ where+ g :: Tr y z-> TrA a x y -> TrA a x z+ g (A i) (TrA j) = TrA (f i j)+++prop_foldl :: forall a.+ Eq a+ => (a -> Int -> a)+ -> TrA a 'K 'K+ -> Queue Tr 'K 'K+ -> Bool+prop_foldl f a q = foldlQ g a q == foldl g a (toList q)+ where+ g :: TrA a y z-> Tr x y -> TrA a x z+ g (TrA j) (A i) = TrA (f j i)