{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Generics.Sum.Internal.Typed
( Context
, derived
, GAsType (..)
) where
import Data.Kind
import GHC.Generics
import GHC.TypeLits (TypeError, ErrorMessage (..), Symbol)
import Data.Generics.Internal.Errors
import Data.Generics.Internal.Families
import Data.Generics.Product.Internal.HList
import Data.Generics.Internal.Profunctor.Iso
import Data.Generics.Internal.Profunctor.Prism
type Context a s
= ( Generic s
, ErrorUnlessOne a s (CollectPartialType (TupleToList a) (Rep s))
, GAsType (Rep s) a
, Defined (Rep s)
(NoGeneric s '[ 'Text "arising from a generic prism focusing on a constructor of type " ':<>: QuoteType a])
(() :: Constraint)
)
derived :: Context a s => Prism' s a
derived = repIso . _GTyped
{-# INLINE derived #-}
type family ErrorUnlessOne (a :: Type) (s :: Type) (ctors :: [Symbol]) :: Constraint where
ErrorUnlessOne _ _ '[_]
= ()
ErrorUnlessOne a s '[]
= TypeError
( 'Text "The type "
':<>: 'ShowType s
':<>: 'Text " does not contain a constructor whose field is of type "
':<>: 'ShowType a
)
ErrorUnlessOne a s cs
= TypeError
( 'Text "The type "
':<>: 'ShowType s
':<>: 'Text " contains multiple constructors whose fields are of type "
':<>: 'ShowType a ':<>: 'Text "."
':$$: 'Text "The choice of constructor is thus ambiguous, could be any of:"
':$$: ShowSymbols cs
)
class GAsType (f :: Type -> Type) (as :: Type) where
_GTyped :: Prism (f x) (f x) as as
instance
( GIsList f f as as
, ListTuple a a as as
) => GAsType (M1 C meta f) a where
_GTyped = mIso . glist . tupled
{-# INLINE _GTyped #-}
instance GSumAsType (HasPartialTypeP (TupleToList a) l) l r a => GAsType (l :+: r) a where
_GTyped = _GSumTyped @(HasPartialTypeP (TupleToList a) l)
{-# INLINE _GTyped #-}
instance GAsType f a => GAsType (M1 D meta f) a where
_GTyped = mIso . _GTyped
{-# INLINE _GTyped #-}
class GSumAsType (contains :: Bool) l r (a :: Type) where
_GSumTyped :: Prism ((l :+: r) x) ((l :+: r) x) a a
instance GAsType l a => GSumAsType 'True l r a where
_GSumTyped = left . _GTyped
{-# INLINE _GSumTyped #-}
instance GAsType r a => GSumAsType 'False l r a where
_GSumTyped = right . _GTyped
{-# INLINE _GSumTyped #-}