{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Vinyl.Core where
#if __GLASGOW_HASKELL__ < 808
import Data.Monoid (Monoid)
#endif
#if __GLASGOW_HASKELL__ < 804
import Data.Semigroup (Semigroup(..))
#endif
import Foreign.Ptr (castPtr, plusPtr)
import Foreign.Storable (Storable(..))
import Data.Functor.Product (Product(Pair))
import Data.List (intercalate)
import Data.Vinyl.Functor
import Data.Vinyl.TypeLevel
import Data.Type.Equality (TestEquality (..), (:~:) (..))
import Data.Type.Coercion (TestCoercion (..), Coercion (..))
import GHC.Generics
import GHC.Types (Constraint, Type)
data Rec :: (u -> *) -> [u] -> * where
RNil :: Rec f '[]
(:&) :: !(f r) -> !(Rec f rs) -> Rec f (r ': rs)
infixr 7 :&
infixr 5 <+>
infixl 8 <<$>>
infixl 8 <<*>>
instance TestEquality f => TestEquality (Rec f) where
testEquality RNil RNil = Just Refl
testEquality (x :& xs) (y :& ys) = do
Refl <- testEquality x y
Refl <- testEquality xs ys
Just Refl
testEquality _ _ = Nothing
instance TestCoercion f => TestCoercion (Rec f) where
testCoercion RNil RNil = Just Coercion
testCoercion (x :& xs) (y :& ys) = do
Coercion <- testCoercion x y
Coercion <- testCoercion xs ys
Just Coercion
testCoercion _ _ = Nothing
rappend
:: Rec f as
-> Rec f bs
-> Rec f (as ++ bs)
rappend RNil ys = ys
rappend (x :& xs) ys = x :& (xs `rappend` ys)
(<+>)
:: Rec f as
-> Rec f bs
-> Rec f (as ++ bs)
(<+>) = rappend
rcombine :: (RMap rs, RApply rs)
=> (forall a. m a -> m a -> m a)
-> (forall a. f a -> m a)
-> (forall a. m a -> g a)
-> Rec f rs
-> Rec f rs
-> Rec g rs
rcombine smash toM fromM x y =
rmap fromM (rapply (rmap (Lift . smash) x') y')
where x' = rmap toM x
y' = rmap toM y
class RMap rs where
rmap :: (forall x. f x -> g x) -> Rec f rs -> Rec g rs
instance RMap '[] where
rmap _ RNil = RNil
{-# INLINE rmap #-}
instance RMap xs => RMap (x ': xs) where
rmap f (x :& xs) = f x :& rmap f xs
{-# INLINE rmap #-}
(<<$>>)
:: RMap rs
=> (forall x. f x -> g x)
-> Rec f rs
-> Rec g rs
(<<$>>) = rmap
{-# INLINE (<<$>>) #-}
(<<&>>)
:: RMap rs
=> Rec f rs
-> (forall x. f x -> g x)
-> Rec g rs
xs <<&>> f = rmap f xs
{-# INLINE (<<&>>) #-}
class RApply rs where
rapply :: Rec (Lift (->) f g) rs
-> Rec f rs
-> Rec g rs
instance RApply '[] where
rapply _ RNil = RNil
{-# INLINE rapply #-}
instance RApply xs => RApply (x ': xs) where
rapply (f :& fs) (x :& xs) = getLift f x :& (fs `rapply` xs)
{-# INLINE rapply #-}
(<<*>>)
:: RApply rs
=> Rec (Lift (->) f g) rs
-> Rec f rs
-> Rec g rs
(<<*>>) = rapply
{-# INLINE (<<*>>) #-}
class RecApplicative rs where
rpure
:: (forall x. f x)
-> Rec f rs
instance RecApplicative '[] where
rpure _ = RNil
{-# INLINE rpure #-}
instance RecApplicative rs => RecApplicative (r ': rs) where
rpure s = s :& rpure s
{-# INLINE rpure #-}
rtraverse
:: Applicative h
=> (forall x. f x -> h (g x))
-> Rec f rs
-> h (Rec g rs)
rtraverse _ RNil = pure RNil
rtraverse f (x :& xs) = (:&) <$> f x <*> rtraverse f xs
{-# INLINABLE rtraverse #-}
rtraverseIn :: forall h f g rs.
(forall a. f a -> g (ApplyToField h a))
-> Rec f rs
-> Rec g (MapTyCon h rs)
rtraverseIn _ RNil = RNil
rtraverseIn f (x :& xs) = f x :& rtraverseIn f xs
{-# INLINABLE rtraverseIn #-}
rsequenceIn :: forall f g (rs :: [Type]). (Traversable f, Applicative g)
=> Rec (f :. g) rs -> Rec g (MapTyCon f rs)
rsequenceIn = rtraverseIn @f (sequenceA . getCompose)
{-# INLINABLE rsequenceIn #-}
rzipWith :: (RMap xs, RApply xs)
=> (forall x. f x -> g x -> h x) -> Rec f xs -> Rec g xs -> Rec h xs
rzipWith f = rapply . rmap (Lift . f)
class RFoldMap rs where
rfoldMapAux :: Monoid m
=> (forall x. f x -> m)
-> m
-> Rec f rs
-> m
instance RFoldMap '[] where
rfoldMapAux _ m RNil = m
{-# INLINE rfoldMapAux #-}
instance RFoldMap xs => RFoldMap (x ': xs) where
rfoldMapAux f m (r :& rs) = rfoldMapAux f (mappend m (f r)) rs
{-# INLINE rfoldMapAux #-}
rfoldMap :: forall rs m f. (Monoid m, RFoldMap rs)
=> (forall x. f x -> m) -> Rec f rs -> m
rfoldMap f = rfoldMapAux f mempty
{-# INLINE rfoldMap #-}
class RecordToList rs where
recordToList :: Rec (Const a) rs -> [a]
instance RecordToList '[] where
recordToList RNil = []
{-# INLINE recordToList #-}
instance RecordToList xs => RecordToList (x ': xs) where
recordToList (x :& xs) = getConst x : recordToList xs
{-# INLINE recordToList #-}
data Dict c a where
Dict
:: c a
=> a
-> Dict c a
class ReifyConstraint c f rs where
reifyConstraint
:: Rec f rs
-> Rec (Dict c :. f) rs
instance ReifyConstraint c f '[] where
reifyConstraint RNil = RNil
{-# INLINE reifyConstraint #-}
instance (c (f x), ReifyConstraint c f xs)
=> ReifyConstraint c f (x ': xs) where
reifyConstraint (x :& xs) = Compose (Dict x) :& reifyConstraint xs
{-# INLINE reifyConstraint #-}
class RPureConstrained c ts where
rpureConstrained :: (forall a. c a => f a) -> Rec f ts
instance RPureConstrained c '[] where
rpureConstrained _ = RNil
{-# INLINE rpureConstrained #-}
instance (c x, RPureConstrained c xs) => RPureConstrained c (x ': xs) where
rpureConstrained f = f :& rpureConstrained @c @xs f
{-# INLINE rpureConstrained #-}
data DictOnly (c :: k -> Constraint) a where
DictOnly :: forall c a. c a => DictOnly c a
withPairedDict :: (c a => f a -> r) -> Product (DictOnly c) f a -> r
withPairedDict f (Pair DictOnly x) = f x
class RPureConstraints cs ts where
rpureConstraints :: (forall a. AllSatisfied cs a => f a) -> Rec f ts
instance RPureConstraints cs '[] where
rpureConstraints _ = RNil
{-# INLINE rpureConstraints #-}
instance (AllSatisfied cs t, RPureConstraints cs ts)
=> RPureConstraints cs (t ': ts) where
rpureConstraints f = f :& rpureConstraints @cs @ts f
{-# INLINE rpureConstraints #-}
instance (RMap rs, ReifyConstraint Show f rs, RecordToList rs)
=> Show (Rec f rs) where
show xs =
(\str -> "{" <> str <> "}")
. intercalate ", "
. recordToList
. rmap (\(Compose (Dict x)) -> Const $ show x)
$ reifyConstraint @Show xs
instance Semigroup (Rec f '[]) where
RNil <> RNil = RNil
instance (Semigroup (f r), Semigroup (Rec f rs))
=> Semigroup (Rec f (r ': rs)) where
(x :& xs) <> (y :& ys) = (x <> y) :& (xs <> ys)
instance Monoid (Rec f '[]) where
mempty = RNil
RNil `mappend` RNil = RNil
instance (Monoid (f r), Monoid (Rec f rs)) => Monoid (Rec f (r ': rs)) where
mempty = mempty :& mempty
(x :& xs) `mappend` (y :& ys) = (mappend x y) :& (mappend xs ys)
instance Eq (Rec f '[]) where
_ == _ = True
instance (Eq (f r), Eq (Rec f rs)) => Eq (Rec f (r ': rs)) where
(x :& xs) == (y :& ys) = (x == y) && (xs == ys)
instance Ord (Rec f '[]) where
compare _ _ = EQ
instance (Ord (f r), Ord (Rec f rs)) => Ord (Rec f (r ': rs)) where
compare (x :& xs) (y :& ys) = mappend (compare x y) (compare xs ys)
instance Storable (Rec f '[]) where
sizeOf _ = 0
alignment _ = 0
peek _ = return RNil
poke _ RNil = return ()
instance (Storable (f r), Storable (Rec f rs))
=> Storable (Rec f (r ': rs)) where
sizeOf _ = sizeOf (undefined :: f r) + sizeOf (undefined :: Rec f rs)
{-# INLINE sizeOf #-}
alignment _ = alignment (undefined :: f r)
{-# INLINE alignment #-}
peek ptr = do !x <- peek (castPtr ptr)
!xs <- peek (ptr `plusPtr` sizeOf (undefined :: f r))
return $ x :& xs
{-# INLINE peek #-}
poke ptr (!x :& xs) = poke (castPtr ptr) x >> poke (ptr `plusPtr` sizeOf (undefined :: f r)) xs
{-# INLINE poke #-}
instance Generic (Rec f '[]) where
type Rep (Rec f '[]) =
C1 ('MetaCons "RNil" 'PrefixI 'False)
(S1 ('MetaSel 'Nothing
'NoSourceUnpackedness
'NoSourceStrictness
'DecidedLazy) U1)
from RNil = M1 (M1 U1)
to (M1 (M1 U1)) = RNil
instance (Generic (Rec f rs)) => Generic (Rec f (r ': rs)) where
type Rep (Rec f (r ': rs)) =
C1 ('MetaCons ":&" ('InfixI 'RightAssociative 7) 'False)
(S1 ('MetaSel 'Nothing
'NoSourceUnpackedness
'SourceStrict
'DecidedStrict)
(Rec0 (f r))
:*:
S1 ('MetaSel 'Nothing
'NoSourceUnpackedness
'NoSourceStrictness
'DecidedLazy)
(Rep (Rec f rs)))
from (x :& xs) = M1 (M1 (K1 x) :*: M1 (from xs))
to (M1 (M1 (K1 x) :*: M1 xs)) = x :& to xs