{-# LANGUAGE CPP #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Vec.DataFamily.SpineStrict.Pigeonhole (
Pigeonhole (..),
gindex,
gtabulate,
gix,
gtraverse,
gitraverse,
gfrom, GFrom,
gto, GTo,
GPigeonholeSize,
) where
import Prelude (Functor (..), fst, uncurry, ($), (.))
import Control.Applicative (Applicative (..), (<$>))
import Control.Arrow (first)
import Data.Fin (Fin (..))
import Data.Functor.Confusing (confusing, fusing, iconfusing)
import Data.Functor.Identity (Identity (..))
import Data.Functor.Product (Product (..))
import Data.Nat (Nat (..))
import Data.Proxy (Proxy (..))
import Data.Vec.DataFamily.SpineStrict (Vec (..), tabulate)
import GHC.Generics ((:*:) (..), M1 (..), Par1 (..), U1 (..))
import qualified Control.Lens.Yocto as Lens
import qualified Data.Fin as F
import qualified Data.Fin.Enum as F
import qualified Data.Type.Nat as N
import qualified Data.Vec.DataFamily.SpineStrict as V
import qualified GHC.Generics as G
#ifdef MIN_VERSION_transformers_compat
import Control.Monad.Trans.Instances ()
#endif
class Pigeonhole f where
type PigeonholeSize f :: Nat
type PigeonholeSize f = GPigeonholeSize f
from :: f x -> Vec (PigeonholeSize f) x
default from :: (G.Generic1 f, GFrom f, PigeonholeSize f ~ GPigeonholeSize f) => f x -> Vec (PigeonholeSize f) x
from = gfrom
to :: Vec (PigeonholeSize f) x -> f x
default to :: (G.Generic1 f, GTo f, PigeonholeSize f ~ GPigeonholeSize f) => Vec (PigeonholeSize f) x -> f x
to = gto
instance Pigeonhole Identity
instance Pigeonhole Proxy
instance (Pigeonhole f, Pigeonhole g, N.InlineInduction (PigeonholeSize f)) => Pigeonhole (Product f g) where
type PigeonholeSize (Product f g) = N.Plus (PigeonholeSize f) (PigeonholeSize g)
to = f . V.split where f (a, b) = Pair (to a) (to b)
from = uncurry (V.++) . g where g (Pair a b) = (from a, from b)
gindex
:: ( G.Generic i, F.GFrom i, G.Generic1 f, GFrom f
, F.GEnumSize i ~ GPigeonholeSize f, N.InlineInduction (GPigeonholeSize f)
)
=> f a -> i -> a
gindex fa i = gfrom fa V.! F.gfrom i
gtabulate
:: ( G.Generic i, F.GTo i, G.Generic1 f, GTo f
, F.GEnumSize i ~ GPigeonholeSize f, N.InlineInduction (GPigeonholeSize f)
)
=> (i -> a) -> f a
gtabulate idx = gto $ tabulate (idx . F.gto)
gix :: ( G.Generic i, F.GFrom i, G.Generic1 t, GTo t, GFrom t
, F.GEnumSize i ~ GPigeonholeSize t, N.InlineInduction (GPigeonholeSize t)
, Functor f
)
=> i -> (a -> f a) -> t a -> f (t a)
gix i = fusing $ \ab ta -> gto <$> ix (F.gfrom i) ab (gfrom ta)
ix :: forall n f a. (N.InlineInduction n, Functor f) => Fin n -> Lens.LensLike' f (Vec n a) a
ix = getIxLens $ N.inlineInduction1 start step where
start :: IxLens f 'Z a
start = IxLens F.absurd
step :: IxLens f m a -> IxLens f ('S m) a
step (IxLens l) = IxLens $ \i -> case i of
FZ -> _head
FS j -> _tail . l j
newtype IxLens f n a = IxLens { getIxLens :: Fin n -> Lens.LensLike' f (Vec n a) a }
_head :: Lens.Lens' (Vec ('S n) a) a
_head f (x ::: xs) = (::: xs) <$> f x
{-# INLINE _head #-}
_tail :: Lens.Lens' (Vec ('S n) a) (Vec n a)
_tail f (x ::: xs) = (x :::) <$> f xs
{-# INLINE _tail #-}
gtraverse
:: ( G.Generic1 t, GFrom t, GTo t
, N.InlineInduction (GPigeonholeSize t)
, Applicative f
)
=> (a -> f b) -> t a -> f (t b)
gtraverse = confusing $ \afb ta -> gto <$> V.traverse afb (gfrom ta)
{-# INLINE gtraverse #-}
gitraverse
:: ( G.Generic i, F.GTo i
, G.Generic1 t, GFrom t, GTo t
, F.GEnumSize i ~ GPigeonholeSize t, N.InlineInduction (GPigeonholeSize t)
, Applicative f
)
=> (i -> a -> f b) -> t a -> f (t b)
gitraverse = iconfusing $ \iafb ta -> gto <$> V.itraverse (\i a -> iafb (F.gto i) a) (gfrom ta)
{-# INLINE gitraverse #-}
type GPigeonholeSize c = PigeonholeSizeRep (G.Rep1 c) N.Nat0
type family PigeonholeSizeRep (c :: * -> *) (n :: Nat) :: Nat where
PigeonholeSizeRep (a :*: b ) n = PigeonholeSizeRep a (PigeonholeSizeRep b n)
PigeonholeSizeRep (M1 _d _c a) n = PigeonholeSizeRep a n
PigeonholeSizeRep Par1 n = 'N.S n
PigeonholeSizeRep U1 n = n
gfrom :: (G.Generic1 c, GFrom c) => c a -> Vec (GPigeonholeSize c) a
gfrom = \x -> gfromRep1 (G.from1 x) VNil
type GFrom c = GFromRep1 (G.Rep1 c)
class GFromRep1 (c :: * -> *) where
gfromRep1 :: c x -> Vec n x -> Vec (PigeonholeSizeRep c n) x
instance (GFromRep1 a, GFromRep1 b) => GFromRep1 (a :*: b) where
gfromRep1 (x :*: y) z = gfromRep1 x (gfromRep1 y z)
instance GFromRep1 a => GFromRep1 (M1 d c a) where
gfromRep1 (M1 a) z = gfromRep1 a z
instance GFromRep1 Par1 where
gfromRep1 (Par1 x) z = x ::: z
instance GFromRep1 U1 where
gfromRep1 _U1 z = z
gto :: forall c a. (G.Generic1 c, GTo c) => Vec (GPigeonholeSize c) a -> c a
gto = \xs -> G.to1 $ fst (gtoRep1 xs :: (G.Rep1 c a, Vec 'N.Z a))
type GTo c = GToRep1 (G.Rep1 c)
class GToRep1 (c :: * -> *) where
gtoRep1 :: Vec (PigeonholeSizeRep c n) x -> (c x, Vec n x)
instance GToRep1 a => GToRep1 (M1 d c a) where
gtoRep1 = first M1 . gtoRep1
instance (GToRep1 a, GToRep1 b) => GToRep1 (a :*: b) where
gtoRep1 xs =
let (a, ys) = gtoRep1 xs
(b, zs) = gtoRep1 ys
in (a :*: b, zs)
instance GToRep1 Par1 where
gtoRep1 (x ::: xs) = (Par1 x, xs)
instance GToRep1 U1 where
gtoRep1 xs = (U1, xs)