vinyl-0.4.2: Data/Vinyl/Core.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Data.Vinyl.Core where
import Data.Vinyl.TyFun
import Control.Applicative
import Data.Monoid
import Data.Vinyl.Idiom.Identity
import Foreign.Ptr (castPtr, plusPtr)
import Foreign.Storable (Storable(..))
-- | A record is parameterized by a universe @u@, list of rows @rs@, a large
-- elimination @el@, and a type constructor @f@ to be applied to the
-- interpretation @el r@ of each of those @r@.
data Rec (el :: TyFun u * -> *) (f :: * -> *) (rrs :: [u]) where
RNil :: Rec el f '[]
(:&) :: !(f (el $ r)) -> !(Rec el f rs) -> Rec el f (r ': rs)
infixr :&
-- | Shorthand for a record with a single field. Lifts the field's
-- value into the chosen functor automatically.
(=:) :: Applicative f => sing k -> el $ k -> Rec el f '[ k ]
_ =: x = pure x :& RNil
-- | Shorthand for a record with a single field. This is useful for
-- @Applicative@ or @Monad@ic intialization of records as in the idiom:
--
-- > dist $ myField <-: someIO <+> yourField <-: otherIO
(<-:) :: sing r -> f (el $ r) -> Rec el f '[r]
_ <-: x = x :& RNil
infixr 6 <-:
-- | Records constructed using the above combinators will often be polymorphic
-- in their interpreter @el@. To avoid providing a type annotation, one can
-- provide their interpreters with a singleton tag and pass that in.
withUniverse :: (forall x. el x) -> Rec el f rs -> Rec el f rs
withUniverse _ x = x
{-# INLINE withUniverse #-}
instance Monoid (Rec el f '[]) where
mempty = RNil
RNil `mappend` RNil = RNil
instance (Monoid (el $ r), Monoid (Rec el f rs), Applicative f) => Monoid (Rec el f (r ': rs)) where
mempty = pure mempty :& mempty
(x :& xs) `mappend` (y :& ys) = liftA2 mappend x y :& (xs `mappend` ys)
instance Eq (Rec el f '[]) where
_ == _ = True
instance (Eq (f (el $ r)), Eq (Rec el f rs)) => Eq (Rec el f (r ': rs)) where
(x :& xs) == (y :& ys) = (x == y) && (xs == ys)
instance Storable (Rec el Identity '[]) where
sizeOf _ = 0
alignment _ = 0
peek _ = return RNil
poke _ RNil = return ()
instance (Storable (el $ r), Storable (Rec el Identity rs)) => Storable (Rec el Identity (r ': rs)) where
sizeOf _ = sizeOf (undefined :: el $ r) + sizeOf (undefined :: Rec el Identity rs)
{-# INLINABLE sizeOf #-}
alignment _ = alignment (undefined :: el $ r)
{-# INLINABLE alignment #-}
peek ptr = do !x <- peek (castPtr ptr)
!xs <- peek (ptr `plusPtr` sizeOf (undefined :: el $ r))
return $ Identity x :& xs
{-# INLINABLE peek #-}
poke ptr (Identity !x :& xs) = poke (castPtr ptr) x >>
poke (ptr `plusPtr` sizeOf (undefined :: el $ r)) xs
{-# INLINEABLE poke #-}