linear-generics-0.1.0.0: tests/Generics/Deriving/Copoint.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE TypeApplications #-}
module Generics.Deriving.Copoint (
-- * GCopoint class
GCopoint(..)
-- * Default method
, gcopointdefault
-- * Internal class
, GCopoint'(..)
) where
import Control.Applicative (WrappedMonad)
import Data.Monoid (Dual)
import qualified Data.Monoid as Monoid (Sum)
import Generics.Linear
import Data.Ord (Down)
import Data.Functor.Identity (Identity)
import Data.Monoid (Alt)
import qualified Data.Functor.Sum as Functor (Sum)
import Data.Semigroup (Arg, First, Last, Max, Min, WrappedMonoid)
--------------------------------------------------------------------------------
-- Generic copoint
--------------------------------------------------------------------------------
-- General copoint may return 'Nothing'
class GCopoint' t where
gcopoint' :: (a -> b) -> t a -> Maybe b
instance GCopoint' V1 where
gcopoint' _ _ = Nothing
instance GCopoint' U1 where
gcopoint' _ U1 = Nothing
instance GCopoint' Par1 where
gcopoint' f (Par1 a) = Just (f a)
instance GCopoint' (K1 i c) where
gcopoint' _ _ = Nothing
instance GCopoint' f => GCopoint' (M1 i c f) where
gcopoint' f (M1 a) = gcopoint' f a
instance GCopoint' f => GCopoint' (MP1 m f) where
gcopoint' f (MP1 a) = gcopoint' f a
instance (GCopoint' f, GCopoint' g) => GCopoint' (f :+: g) where
gcopoint' f (L1 a) = gcopoint' f a
gcopoint' f (R1 a) = gcopoint' f a
-- Favours left "hole" for copoint
instance (GCopoint' f, GCopoint' g) => GCopoint' (f :*: g) where
gcopoint' f (a :*: b) = case (gcopoint' f a) of
Just x -> Just x
Nothing -> gcopoint' f b
instance (GCopoint' f, GCopoint g) => GCopoint' (f :.: g) where
gcopoint' f (Comp1 x) = gcopoint' (f . gcopoint) x
class GCopoint d where
gcopoint :: d a -> a
default gcopoint :: (Generic1 d, GCopoint' (Rep1 d))
=> (d a -> a)
gcopoint = gcopointdefault
gcopointdefault :: (Generic1 d, GCopoint' (Rep1 d))
=> d a -> a
gcopointdefault x = case (gcopoint' id . from1 $ x) of
Just x' -> x'
Nothing -> error "Data type is not copointed"
-- instance (Generic1 d, GCopoint' (Rep1 d)) => GCopoint d
-- Base types instances
instance GCopoint ((,) a)
instance GCopoint ((,,) a b)
instance GCopoint ((,,,) a b c)
instance GCopoint ((,,,,) a b c d)
instance GCopoint ((,,,,,) a b c d e)
instance GCopoint ((,,,,,,) a b c d e f)
instance GCopoint f => GCopoint (Alt f)
instance GCopoint (Arg a)
instance GCopoint Down
instance GCopoint Dual
instance GCopoint First
instance GCopoint Identity
instance GCopoint Last
instance GCopoint Max
instance GCopoint Min
instance (GCopoint f, GCopoint g) => GCopoint (Functor.Sum f g)
instance GCopoint Monoid.Sum
instance GCopoint m => GCopoint (WrappedMonad m)
instance GCopoint WrappedMonoid