{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Data.RAVec (
RAVec (..),
empty,
singleton,
cons,
withCons,
head,
last,
toList,
toNonEmpty,
fromList,
reifyNonEmpty,
(!),
tabulate,
foldMap,
foldMap1,
ifoldMap,
ifoldMap1,
foldr,
ifoldr,
map,
imap,
traverse,
itraverse,
#ifdef MIN_VERSION_semigroupoids
traverse1,
itraverse1,
#endif
zipWith,
izipWith,
universe,
repeat,
liftArbitrary,
liftShrink,
) where
import Prelude
(Bool (..), Eq (..), Functor (..), Int, Maybe (..), Ord (..), Show, ($), (.))
import Control.Applicative (Applicative (..), (<$>))
import Control.DeepSeq (NFData (..))
import Data.Bin (Bin (..))
import Data.Bin.Pos (Pos (..))
import Data.Hashable (Hashable (..))
import Data.List.NonEmpty (NonEmpty (..))
import Data.Monoid (Monoid (..))
import Data.Semigroup (Semigroup (..))
import Data.Type.Bin (SBin (..), SBinI (..), SBinPI (..))
import Data.Type.Equality ((:~:) (..))
import Data.Typeable (Typeable)
import qualified Data.RAVec.NonEmpty as NE
import qualified Data.Type.Bin as B
import qualified Data.Foldable as I (Foldable (..))
import qualified Data.Traversable as I (Traversable (..))
import qualified Test.QuickCheck as QC
#ifdef MIN_VERSION_distributive
import qualified Data.Distributive as I (Distributive (..))
#ifdef MIN_VERSION_adjunctions
import qualified Data.Functor.Rep as I (Representable (..))
#endif
#endif
#ifdef MIN_VERSION_semigroupoids
import Data.Functor.Apply (Apply (..))
import qualified Data.Semigroup.Foldable as I (Foldable1 (..))
import qualified Data.Semigroup.Traversable as I (Traversable1 (..))
#endif
import Data.RAVec.NonEmpty (NERAVec (..))
data RAVec (b :: Bin) a where
Empty :: RAVec 'BZ a
NonEmpty :: NERAVec b a -> RAVec ('BP b) a
deriving (Typeable)
deriving instance Eq a => Eq (RAVec b a)
deriving instance Show a => Show (RAVec b a)
instance Ord a => Ord (RAVec b a) where
compare xs ys = compare (toList xs) (toList ys)
instance Functor (RAVec b) where
fmap = map
instance I.Foldable (RAVec b) where
foldMap = foldMap
foldr = foldr
#if MIN_VERSION_base(4,8,0)
null = null
#endif
instance I.Traversable (RAVec b) where
traverse = traverse
#ifdef MIN_VERSION_semigroupoids
instance b ~ 'BP n => I.Foldable1 (RAVec b) where
foldMap1 = foldMap1
toNonEmpty = toNonEmpty
instance b ~ 'BP n => I.Traversable1 (RAVec b) where
traverse1 = traverse1
#endif
instance NFData a => NFData (RAVec b a) where
rnf Empty = ()
rnf (NonEmpty ral) = rnf ral
instance Hashable a => Hashable (RAVec b a) where
hashWithSalt salt = hashWithSalt salt . toList
instance SBinI b => Applicative (RAVec b) where
pure = repeat
(<*>) = zipWith ($)
x <* _ = x
_ *> x = x
#if MIN_VERSION_base(4,10,0)
liftA2 = zipWith
#endif
#ifdef MIN_VERSION_distributive
instance SBinI b => I.Distributive (RAVec b) where
distribute f = tabulate (\k -> fmap (! k) f)
#ifdef MIN_VERSION_adjunctions
instance SBinI b => I.Representable (RAVec b) where
type Rep (RAVec b) = Pos b
index = (!)
tabulate = tabulate
#endif
#endif
instance Semigroup a => Semigroup (RAVec b a) where
(<>) = zipWith (<>)
instance (Monoid a, SBinI b) => Monoid (RAVec b a) where
mempty = repeat mempty
mappend = zipWith mappend
#ifdef MIN_VERSION_semigroupoids
instance Apply (RAVec b) where
(<.>) = zipWith ($)
liftF2 = zipWith
_ .> x = x
x <. _ = x
#endif
empty :: RAVec B.Bin0 a
empty = Empty
singleton :: a -> RAVec B.Bin1 a
singleton = NonEmpty . NE.singleton
cons :: a -> RAVec b a -> RAVec (B.Succ b) a
cons x Empty = singleton x
cons x (NonEmpty xs) = NonEmpty (NE.cons x xs)
withCons :: SBinI b => a -> RAVec b a -> (SBinPI (B.Succ' b) => RAVec (B.Succ b) a -> r) -> r
withCons = go sbin where
go :: SBin b -> a -> RAVec b a -> (SBinPI (B.Succ' b) => RAVec (B.Succ b) a -> r) -> r
go SBZ x Empty k = k (singleton x)
go SBP x (NonEmpty xs) k = NE.withCons x xs $ k . NonEmpty
head :: RAVec ('BP b) a -> a
head (NonEmpty ral) = NE.head ral
last :: RAVec ('BP b) a -> a
last (NonEmpty ral) = NE.last ral
toList :: RAVec b a -> [a]
toList Empty = []
toList (NonEmpty ral) = NE.toList ral
toNonEmpty :: RAVec ('BP b) a -> NonEmpty a
toNonEmpty (NonEmpty ral) = NE.toNonEmpty ral
fromList :: forall b a. SBinI b => [a] -> Maybe (RAVec b a)
fromList xs = reifyList xs mk where
mk :: forall c. SBinI c => RAVec c a -> Maybe (RAVec b a)
mk ral = do
Refl <- B.eqBin :: Maybe (b :~: c)
Just ral
reifyList :: [a] -> (forall b. SBinI b => RAVec b a -> r) -> r
reifyList [] k = k Empty
reifyList (x:xs) k = reifyList xs $ \ral -> withCons x ral k
reifyNonEmpty :: NonEmpty a -> (forall b. SBinPI b => RAVec ('BP b) a -> r) -> r
reifyNonEmpty xs k = NE.reifyNonEmpty xs $ k . NonEmpty
(!) :: RAVec b a -> Pos b -> a
(!) Empty p = case p of {}
(!) (NonEmpty b) (Pos i) = b NE.! i
tabulate :: forall b a. SBinI b => (Pos b -> a) -> RAVec b a
tabulate f = case sbin :: SBin b of
SBZ -> Empty
SBP -> NonEmpty (NE.tabulate (f . Pos))
foldMap :: Monoid m => (a -> m) -> RAVec n a -> m
foldMap _ Empty = mempty
foldMap f (NonEmpty r) = NE.foldMap f r
ifoldMap :: Monoid m => (Pos b -> a -> m) -> RAVec b a -> m
ifoldMap _ Empty = mempty
ifoldMap f (NonEmpty r) = NE.ifoldMap (f . Pos) r
foldMap1 :: Semigroup m => (a -> m) -> RAVec ('BP b) a -> m
foldMap1 f (NonEmpty r) = NE.foldMap1 f r
ifoldMap1 :: Semigroup m => (Pos ('BP b) -> a -> m) -> RAVec ('BP b) a -> m
ifoldMap1 f (NonEmpty r) = NE.ifoldMap1 (f . Pos) r
foldr :: (a -> b -> b) -> b -> RAVec n a -> b
foldr _ z Empty = z
foldr f z (NonEmpty ral) = NE.foldr f z ral
ifoldr :: (Pos n -> a -> b -> b) -> b -> RAVec n a -> b
ifoldr _ z Empty = z
ifoldr f z (NonEmpty ral) = NE.ifoldr (f . Pos) z ral
null :: RAVec n a -> Bool
null Empty = True
null (NonEmpty _) = False
map :: (a -> b) -> RAVec n a -> RAVec n b
map _ Empty = Empty
map f (NonEmpty r) = NonEmpty (NE.map f r)
imap :: (Pos n -> a -> b) -> RAVec n a -> RAVec n b
imap _ Empty = Empty
imap f (NonEmpty r) = NonEmpty (NE.imap (f . Pos) r)
traverse :: Applicative f => (a -> f b) -> RAVec n a -> f (RAVec n b)
traverse _ Empty = pure empty
traverse f (NonEmpty ral) = NonEmpty <$> NE.traverse f ral
itraverse :: Applicative f => (Pos n -> a -> f b) -> RAVec n a -> f (RAVec n b)
itraverse _ Empty = pure Empty
itraverse f (NonEmpty r) = NonEmpty <$> NE.itraverse (f . Pos) r
#ifdef MIN_VERSION_semigroupoids
traverse1 :: Apply f => (a -> f b) -> RAVec ('BP n) a -> f (RAVec ('BP n) b)
traverse1 f (NonEmpty r) = NonEmpty <$> NE.traverse1 f r
itraverse1 :: Apply f => (Pos ('BP n) -> a -> f b) -> RAVec ('BP n) a -> f (RAVec ('BP n) b)
itraverse1 f (NonEmpty r) = NonEmpty <$> NE.itraverse1 (f . Pos) r
#endif
zipWith :: (a -> b -> c) -> RAVec n a -> RAVec n b -> RAVec n c
zipWith _ Empty Empty = Empty
zipWith f (NonEmpty xs) (NonEmpty ys) = NonEmpty (NE.zipWith f xs ys)
izipWith :: (Pos n -> a -> b -> c) -> RAVec n a -> RAVec n b -> RAVec n c
izipWith _ Empty Empty = Empty
izipWith f (NonEmpty xs) (NonEmpty ys) = NonEmpty (NE.izipWith (f . Pos) xs ys)
repeat :: forall b a. SBinI b => a -> RAVec b a
repeat x = case sbin :: SBin b of
SBZ -> Empty
SBP -> NonEmpty (NE.repeat x)
universe :: forall b. SBinI b => RAVec b (Pos b)
universe = case sbin :: SBin b of
SBZ -> Empty
SBP -> NonEmpty (fmap Pos NE.universe)
liftArbitrary :: B.SBinI b => QC.Gen a -> QC.Gen (RAVec b a)
liftArbitrary = liftArbitrary
liftShrink :: (a -> [a]) -> RAVec b a -> [RAVec b a]
liftShrink _ Empty = []
liftShrink shr (NonEmpty r) = NonEmpty <$> NE.liftShrink shr r
instance B.SBinI b => QC.Arbitrary1 (RAVec b) where
liftArbitrary = liftArbitrary
liftShrink = liftShrink
instance (B.SBinI b, QC.Arbitrary a) => QC.Arbitrary (RAVec b a) where
arbitrary = QC.arbitrary1
shrink = QC.shrink1
instance QC.CoArbitrary a => QC.CoArbitrary (RAVec b a) where
coarbitrary Empty = QC.variant (0 :: Int)
coarbitrary (NonEmpty r) = QC.variant (1 :: Int) . QC.coarbitrary r
instance (B.SBinI b, QC.Function a) => QC.Function (RAVec b a) where
function = case B.sbin :: B.SBin b of
SBZ -> QC.functionMap (\Empty -> ()) (\() -> Empty)
SBP -> QC.functionMap (\(NonEmpty r) -> r) NonEmpty