{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE Arrows #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Cell.Util.Traversable where
-- base
import qualified Control.Category as C
import Control.Monad
import Data.Functor.Identity
import Data.List
import Data.Maybe
import GHC.TypeLits (KnownNat)
-- containers
import Data.Map (Map)
import Data.Sequence (Seq)
-- transformers
import Control.Monad.Trans.Reader
import Control.Monad.Trans.State.Lazy
-- vector-sized
import qualified Data.Vector.Sized as V
-- test-framework
import Test.Framework
-- test-framework-quickcheck2
import Test.Framework.Providers.QuickCheck2
-- QuickCheck
import Test.QuickCheck hiding (output)
-- essence-of-live-coding
import LiveCoding
import Util
type TestTraversables = Traversables '[Maybe, [], V.Vector 10, Seq, Map Int]
testTraverse' :: Test
testTraverse' =
testGroup
"Traversing unit tests"
[ genTraversableTests' @TestTraversables "traverse' (arr f) = arr (f <$>)" $
makeTraversableTest (traverseArrLaw @Int @Int)
, genTraversableTests' @TestTraversables
"traverse' works as expected for any Cell Identy Int Int created with constructor Cell"
$ makeTraversableTest (traverseCellTest @Int @Int @Int)
, testProperty "traverse' by itself does not force the entire list (ArrM)" $
CellSimulation
{ cell = arr head
, input = [1 : error "Bang !"]
, output = [1]
}
, testProperty "traverse' by itself does not force the entire list (Cell)" $
CellSimulation
{ cell = toCell $ arr head
, input = [1 : error "Bang !"]
, output = [1]
}
]
traverseArrLaw ::
forall a b t.
(Traversable t) =>
Proxy t ->
[t a] ->
Fun a b ->
CellIdentitySimulation (t a) (t b)
traverseArrLaw _ joinInput (Fn f) =
CellIdentitySimulation
{ cellL = arr (f <$>)
, cellR = traverse' (arr f)
, ..
}
traverseCellTest ::
forall s a b t.
(Traversable t, Data s) =>
Proxy t ->
s ->
Fun (s, a) (b, s) ->
[t a] ->
CellSimulation (t a) (t b)
traverseCellTest _ s (Fn2 f) input =
CellSimulation
{ cell = traverse' (Cell s (\s a -> pure $ f s a))
, output = runIdentity $ evalStateT (traverse (traverse (\a -> StateT (Identity . (`f` a)))) input) s
, ..
}
makeTraversableTest :: forall (t :: * -> *) a. (Testable a, Typeable t) => (Proxy t -> a) -> Proxy t -> Test
makeTraversableTest a _ = testProperty (show (typeRep (Proxy :: Proxy t))) (a (Proxy :: Proxy t))
-- | A data type to store types which are instances of 'Traversable'.
data Traversables :: [* -> *] -> *
-- | A type class for induction on the type-level list containing the Traversables.
class GenTests a where
genTraversableTests ::
(forall (t :: * -> *). (Arbitrary (t Int), Show (t Int), Eq (t Int), Traversable t, Typeable t) => Proxy t -> Test) ->
Proxy a ->
[Test]
instance GenTests (Traversables '[]) where
genTraversableTests _ _ = []
instance
(GenTests (Traversables xs), Arbitrary (x Int), Show (x Int), Eq (x Int), Traversable x, Typeable x) =>
GenTests (Traversables (x ': xs))
where
genTraversableTests f _ = f (Proxy :: Proxy x) : genTraversableTests f (Proxy :: Proxy (Traversables xs))
genTraversableTests' ::
forall a.
(GenTests a) =>
String ->
(forall (t :: * -> *). (Arbitrary (t Int), Show (t Int), Eq (t Int), Traversable t, Typeable t) => Proxy t -> Test) ->
Test
genTraversableTests' message f = testGroup message $ genTraversableTests f (Proxy :: Proxy a)
instance (Arbitrary a, KnownNat n) => Arbitrary (V.Vector n a) where
arbitrary = V.replicateM arbitrary
shrink = V.mapM shrink