{-# LANGUAGE CPP                        #-}
{-# LANGUAGE DataKinds                  #-}
{-# LANGUAGE DeriveFoldable             #-}
{-# LANGUAGE DeriveFunctor              #-}
{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE DeriveTraversable          #-}
{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE GADTs                      #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE PolyKinds                  #-}
{-# LANGUAGE ScopedTypeVariables        #-}
{-# LANGUAGE StandaloneDeriving         #-}
{-# LANGUAGE TypeFamilies               #-}
{-# LANGUAGE TypeOperators              #-}
module Data.Vinyl.Functor
  ( 
    
    
    Identity(..)
  , Thunk(..)
  , Lift(..)
  , ElField(..)
  , Compose(..), onCompose
  , (:.)
  , Const(..)
    
    
    
    
    
  ) where
import Data.Proxy
#if __GLASGOW_HASKELL__ < 804
import Data.Semigroup
#endif
import Foreign.Ptr (castPtr)
import Foreign.Storable
import GHC.Generics
import GHC.TypeLits
import GHC.Types (Type)
newtype Identity a
  = Identity { getIdentity :: a }
    deriving ( Functor
             , Foldable
             , Traversable
             , Storable
             , Eq
             , Ord
             , Generic
             )
data Thunk a
  = Thunk { getThunk :: a }
    deriving ( Functor
             , Foldable
             , Traversable
             )
newtype Lift (op :: l -> l' -> *) (f :: k -> l) (g :: k -> l') (x :: k)
  = Lift { getLift :: op (f x) (g x) }
newtype Compose (f :: l -> *) (g :: k -> l) (x :: k)
  = Compose { getCompose :: f (g x) }
    deriving (Storable, Generic)
instance Semigroup (f (g a)) => Semigroup (Compose f g a) where
  Compose x <> Compose y = Compose (x <> y)
instance Monoid (f (g a)) => Monoid (Compose f g a) where
  mempty = Compose mempty
  mappend (Compose x) (Compose y) = Compose (mappend x y)
onCompose :: (f (g a) -> h (k a)) -> (f :. g) a -> (h :. k) a
onCompose f = Compose . f . getCompose
type f :. g = Compose f g
infixr 9 :.
newtype Const (a :: *) (b :: k)
  = Const { getConst :: a }
    deriving ( Functor
             , Foldable
             , Traversable
             , Storable
             , Generic
             )
data ElField (field :: (Symbol, Type)) where
  Field :: KnownSymbol s => !t -> ElField '(s,t)
deriving instance Eq t => Eq (ElField '(s,t))
deriving instance Ord t => Ord (ElField '(s,t))
instance KnownSymbol s => Generic (ElField '(s,a)) where
  type Rep (ElField '(s,a)) = C1 ('MetaCons s 'PrefixI 'False) (Rec0 a)
  from (Field x) = M1 (K1 x)
  to (M1 (K1 x)) = Field x
instance (Num t, KnownSymbol s) => Num (ElField '(s,t)) where
  Field x + Field y = Field (x+y)
  Field x * Field y = Field (x*y)
  abs (Field x) = Field (abs x)
  signum (Field x) = Field (signum x)
  fromInteger = Field . fromInteger
  negate (Field x) = Field (negate x)
instance Semigroup t => Semigroup (ElField '(s,t)) where
  Field x <> Field y = Field (x <> y)
instance (KnownSymbol s, Monoid t) => Monoid (ElField '(s,t)) where
  mempty = Field mempty
  mappend (Field x) (Field y) = Field (mappend x y)
instance (Real t, KnownSymbol s) => Real (ElField '(s,t)) where
  toRational (Field x) = toRational x
instance (Fractional t, KnownSymbol s) => Fractional (ElField '(s,t)) where
  fromRational = Field . fromRational
  Field x / Field y = Field (x / y)
instance (Floating t, KnownSymbol s) => Floating (ElField '(s,t)) where
  pi = Field pi
  exp (Field x) = Field (exp x)
  log (Field x) = Field (log x)
  sin (Field x) = Field (sin x)
  cos (Field x) = Field (cos x)
  asin (Field x) = Field (asin x)
  acos (Field x) = Field (acos x)
  atan (Field x) = Field (atan x)
  sinh (Field x) = Field (sinh x)
  cosh (Field x) = Field (cosh x)
  asinh (Field x) = Field (asinh x)
  acosh (Field x) = Field (acosh x)
  atanh (Field x) = Field (atanh x)
instance (RealFrac t, KnownSymbol s) => RealFrac (ElField '(s,t)) where
  properFraction (Field x) = fmap Field (properFraction x)
instance (Show t, KnownSymbol s) => Show (ElField '(s,t)) where
  show (Field x) = symbolVal (Proxy::Proxy s) ++" :-> "++show x
instance forall s t. (KnownSymbol s, Storable t)
    => Storable (ElField '(s,t)) where
  sizeOf _ = sizeOf (undefined::t)
  alignment _ = alignment (undefined::t)
  peek ptr = Field `fmap` peek (castPtr ptr)
  poke ptr (Field x) = poke (castPtr ptr) x
instance Show a => Show (Const a b) where
  show (Const x) = "(Const "++show x ++")"
instance Eq a => Eq (Const a b) where
  Const x == Const y = x == y
instance (Functor f, Functor g) => Functor (Compose f g) where
  fmap f (Compose x) = Compose (fmap (fmap f) x)
instance (Foldable f, Foldable g) => Foldable (Compose f g) where
  foldMap f (Compose t) = foldMap (foldMap f) t
instance (Traversable f, Traversable g) => Traversable (Compose f g) where
  traverse f (Compose t) = Compose <$> traverse (traverse f) t
instance (Applicative f, Applicative g) => Applicative (Compose f g) where
  pure x = Compose (pure (pure x))
  Compose f <*> Compose x = Compose ((<*>) <$> f <*> x)
instance Show (f (g a)) => Show (Compose f g a) where
  show (Compose x) = show x
instance Applicative Identity where
  pure = Identity
  Identity f <*> Identity x = Identity (f x)
instance Monad Identity where
  return = Identity
  Identity x >>= f = f x
instance Show a => Show (Identity a) where
  show (Identity x) = show x
instance Applicative Thunk where
  pure = Thunk
  (Thunk f) <*> (Thunk x) = Thunk (f x)
instance Monad Thunk where
  return = Thunk
  (Thunk x) >>= f = f x
instance Show a => Show (Thunk a) where
  show (Thunk x) = show x
instance (Functor f, Functor g) => Functor (Lift (,) f g) where
  fmap f (Lift (x, y)) = Lift (fmap f x, fmap f y)
instance (Functor f, Functor g) => Functor (Lift Either f g) where
  fmap f (Lift (Left x)) = Lift . Left . fmap f $ x
  fmap f (Lift (Right x)) = Lift . Right . fmap f $ x
instance (Applicative f, Applicative g) => Applicative (Lift (,) f g) where
  pure x = Lift (pure x, pure x)
  Lift (f, g) <*> Lift (x, y) = Lift (f <*> x, g <*> y)