variadic-0.0.0.0: src/Control/Variadic/Generic/Internal.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Control.Variadic.Generic.Internal where
import Control.Variadic
import Data.Kind (Constraint)
import Data.Proxy (Proxy(Proxy))
import GHC.Generics
import GHC.TypeLits
-- | Runs @hoist@ on the return values each field of @r@
-- with the given natural transformation function, ignoring
-- the @close@ field, if it exists.
ghoist
:: ( Generic (r f)
, Generic (r g)
, GHoist (Rep (r f)) (Rep (r g)) f g '["close"]
)
=> (forall x. f x -> g x)
-> r f
-> r g
ghoist = ghoist' (Proxy @'["close"])
-- | Runs @hoist@ on the return values each field of @r@
-- with the given natural transformation function; no fields
-- are ignored.
ghoist0
:: ( Generic (r f)
, Generic (r g)
, GHoist (Rep (r f)) (Rep (r g)) f g '[]
)
=> (forall x. f x -> g x)
-> r f
-> r g
ghoist0 = ghoist' (Proxy @'[])
-- | Runs @hoist@ on the return values each field of @r@
-- with the given natural transformation function.
-- A supplied of @ignored@ fields is provided to signal which
-- fields should not be transformed.
ghoist'
:: ( Generic (r f)
, Generic (r g)
, GHoist (Rep (r f)) (Rep (r g)) f g ignored
)
=> proxy ignored
-> (forall x. f x -> g x)
-> r f
-> r g
ghoist' proxy f = to . gghoist proxy f . from
class GHoist (i :: * -> *) (o :: * -> *) (f :: * -> *) (g :: * -> *) (ignored :: [Symbol]) where
gghoist :: proxy ignored -> (forall x. f x -> g x) -> i p -> o p
instance (GHoist i o f g ignored) => GHoist (M1 D c i) (M1 D c o) f g ignored where
gghoist proxy f (M1 i) = M1 (gghoist proxy f i)
instance (GHoist i o f g ignored) => GHoist (M1 C c i) (M1 C c o) f g ignored where
gghoist proxy f (M1 i) = M1 (gghoist proxy f i)
instance {-# OVERLAPPING #-}
( VerifyIgnored n a ignored
) => GHoist
(M1 S ('MetaSel ('Just n) su ss ds) (K1 R a))
(M1 S ('MetaSel ('Just n) su ss ds) (K1 R a))
f g ignored
where
gghoist _proxy _f (M1 i) = M1 i
instance
( GHoist (K1 R i) (K1 R o) f g ignored
, VerifyNotIgnored n i ignored
) => GHoist
(M1 S ('MetaSel ('Just n) su ss ds) (K1 R i))
(M1 S ('MetaSel ('Just n) su ss ds) (K1 R o))
f g ignored
where
gghoist proxy f (M1 i) = M1 (gghoist proxy f i)
instance
( GHoist i1 o1 f g ignored
, GHoist i2 o2 f g ignored
) => GHoist (i1 :*: i2) (o1 :*: o2) f g ignored
where
gghoist proxy f (i1 :*: i2) = gghoist proxy f i1 :*: gghoist proxy f i2
instance
( Monad f
, IsVariadic vf args (f a)
, IsVariadic vg args (g a)
) => GHoist (K1 R vf) (K1 R vg) f g ignored
where
gghoist _proxy f (K1 vf) = K1 (vhoist f vf)
type VerifyIgnored e a es = VerifyIgnoredGo e a es es
type family VerifyIgnoredGo e a es orig :: Constraint where
VerifyIgnoredGo x a (x ': xs) orig = ()
VerifyIgnoredGo y a (x ': xs) orig = VerifyIgnoredGo y a xs orig
VerifyIgnoredGo x a '[] orig =
TypeError
( 'Text "Field:"
':$$: 'Text " "
':<>: 'Text x
':<>: 'Text " :: "
':<>: 'ShowType a
':$$: 'Text "cannot be ghoist-ed with the supplied "
':<>: 'Text "function and was not in the ignored fields list: "
':<>: 'ShowType orig
)
type VerifyNotIgnored e a es = VerifyNotIgnoredGo e a es es
type family VerifyNotIgnoredGo e a es orig :: Constraint where
VerifyNotIgnoredGo x a (x ': xs) orig =
TypeError
( 'Text "Field:"
':$$: 'Text " "
':<>: 'Text x
':<>: 'Text " :: "
':<>: 'ShowType a
':$$: 'Text "must be ghoist-ed but was present in the ignored "
':<>: 'Text "fields list: "
':<>: 'ShowType orig
)
VerifyNotIgnoredGo y a (x ': xs) orig = VerifyNotIgnoredGo y a xs orig
VerifyNotIgnoredGo x a '[] orig = ()