{-# LANGUAGE AllowAmbiguousTypes, DataKinds, ExplicitNamespaces,
FunctionalDependencies, PatternSynonyms, TypeFamilies,
UndecidableInstances #-}
module Named.Internal where
import Prelude (id, Maybe(..))
import Data.Maybe (fromMaybe)
import Data.Functor.Identity (Identity(..))
import Data.Kind (Type)
import GHC.TypeLits (Symbol, TypeError, ErrorMessage(..))
import GHC.OverloadedLabels (IsLabel(..))
import Data.Type.Equality (type (~))
newtype NamedF f (a :: Type) (name :: Symbol) =
ArgF (f a)
pattern Arg :: a -> name :! a
pattern $mArg :: forall {r} {a} {name :: Symbol}.
(name :! a) -> (a -> r) -> ((# #) -> r) -> r
$bArg :: forall a (name :: Symbol). a -> name :! a
Arg a = ArgF (Identity a)
{-# COMPLETE Arg #-}
type name :! a = NamedF Identity a name
type name :? a = NamedF Maybe a name
class InjValue f where
injValue :: a -> f a
instance InjValue Identity where
injValue :: forall a. a -> Identity a
injValue = a -> Identity a
forall a. a -> Identity a
Identity
instance InjValue Maybe where
injValue :: forall a. a -> Maybe a
injValue = a -> Maybe a
forall a. a -> Maybe a
Just
instance (name ~ name', a ~ a', InjValue f) => IsLabel name (a -> NamedF f a' name') where
fromLabel :: a -> NamedF f a' name'
fromLabel a
a = f a' -> NamedF f a' name'
forall (f :: * -> *) a (name :: Symbol). f a -> NamedF f a name
ArgF (a' -> f a'
forall a. a -> f a
forall (f :: * -> *) a. InjValue f => a -> f a
injValue a
a'
a)
{-# INLINE fromLabel #-}
newtype Param p = Param p
instance (p ~ NamedF f a name, InjValue f) => IsLabel name (a -> Param p) where
fromLabel :: a -> Param p
fromLabel a
a = p -> Param p
forall p. p -> Param p
Param (forall (x :: Symbol) a. IsLabel x a => a
fromLabel @name a
a)
{-# INLINE fromLabel #-}
param :: Name name -> a -> Param (name :! a)
param :: forall (name :: Symbol) a. Name name -> a -> Param (name :! a)
param Name name
_ a
a = (name :! a) -> Param (name :! a)
forall p. p -> Param p
Param (a -> name :! a
forall a (name :: Symbol). a -> name :! a
Arg a
a)
paramF :: Name name -> f a -> Param (NamedF f a name)
paramF :: forall (name :: Symbol) (f :: * -> *) a.
Name name -> f a -> Param (NamedF f a name)
paramF Name name
_ f a
fa = NamedF f a name -> Param (NamedF f a name)
forall p. p -> Param p
Param (f a -> NamedF f a name
forall (f :: * -> *) a (name :: Symbol). f a -> NamedF f a name
ArgF f a
fa)
(!) :: forall p fn fn'. WithParam p fn fn' => fn -> Param p -> fn'
fn
fn ! :: forall p fn fn'. WithParam p fn fn' => fn -> Param p -> fn'
! Param p
p = Param p -> fn -> fn'
forall p fn fn'. WithParam p fn fn' => Param p -> fn -> fn'
with Param p
p fn
fn
{-# INLINE (!) #-}
infixl 9 !
class WithParam p fn fn' | p fn -> fn' where
with :: Param p -> fn -> fn'
instance WithParam' (Decide p fn) p fn fn' => WithParam p fn fn' where
with :: Param p -> fn -> fn'
with (Param p
p) fn
fn = forall (ds :: [*]) p fn fn'.
WithParam' ds p fn fn' =>
p -> fn -> fn'
withParam @(Decide p fn) p
p fn
fn
{-# INLINE with #-}
data Defaults = Defaults
defaults :: Param Defaults
defaults :: Param Defaults
defaults = Defaults -> Param Defaults
forall p. p -> Param p
Param Defaults
Defaults
data Name (name :: Symbol) = Name
instance name ~ name' => IsLabel name' (Name name) where
fromLabel :: Name name
fromLabel = Name name
forall (name :: Symbol). Name name
Name
{-# INLINE fromLabel #-}
arg :: Name name -> name :! a -> a
arg :: forall (name :: Symbol) a. Name name -> (name :! a) -> a
arg Name name
_ (ArgF (Identity a
a)) = a
a
{-# INLINE arg #-}
argF :: Name name -> NamedF f a name -> f a
argF :: forall (name :: Symbol) (f :: * -> *) a.
Name name -> NamedF f a name -> f a
argF Name name
_ (ArgF f a
fa) = f a
fa
{-# INLINE argF #-}
argDef :: Name name -> a -> name :? a -> a
argDef :: forall (name :: Symbol) a. Name name -> a -> (name :? a) -> a
argDef Name name
_ a
d (ArgF Maybe a
fa) = a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe a
d Maybe a
fa
data DApply
data DFill
data DPass
type family Decide (p :: Type) (fn :: Type) :: [Type] where
Decide (NamedF f' a' name) (NamedF f a name -> r) = '[DApply]
Decide Defaults (NamedF Maybe a name -> r) = DFill : Decide Defaults r
Decide p (x -> r) = DPass : Decide p r
Decide (NamedF f' a' name) t =
TypeError (Text "Named parameter '" :<>: Text name :<>:
Text "' was supplied, but not expected")
Decide Defaults t = '[]
class WithParam' (ds :: [Type]) p fn fn' | ds p fn -> fn' where
withParam :: p -> fn -> fn'
instance fn ~ fn' => WithParam' '[] p fn fn' where
withParam :: p -> fn -> fn'
withParam p
_ = fn -> fn
fn -> fn'
forall a. a -> a
id
{-# INLINE withParam #-}
instance
( WithParam' ds p r r',
fn ~ (p -> r),
fn' ~ r'
) => WithParam' (DApply : ds) p fn fn'
where
withParam :: p -> fn -> fn'
withParam p
p fn
fn = forall (ds :: [*]) p fn fn'.
WithParam' ds p fn fn' =>
p -> fn -> fn'
withParam @ds p
p (fn
p -> r
fn p
p)
{-# INLINE withParam #-}
instance
( WithParam' ds p r r',
fn ~ (x -> r),
fn' ~ (x -> r')
) => WithParam' (DPass : ds) p fn fn'
where
withParam :: p -> fn -> fn'
withParam p
a fn
fn = \x
x -> forall (ds :: [*]) p fn fn'.
WithParam' ds p fn fn' =>
p -> fn -> fn'
withParam @ds p
a (fn
x -> r
fn x
x)
{-# INLINE withParam #-}
instance
( WithParam' ds p r r',
fn ~ (NamedF f x name -> r),
fn' ~ r',
f ~ Maybe
) => WithParam' (DFill : ds) p fn fn'
where
withParam :: p -> fn -> fn'
withParam p
p fn
fn = forall (ds :: [*]) p fn fn'.
WithParam' ds p fn fn' =>
p -> fn -> fn'
withParam @ds p
p (fn
NamedF Maybe x name -> r
fn (Maybe x -> NamedF Maybe x name
forall (f :: * -> *) a (name :: Symbol). f a -> NamedF f a name
ArgF Maybe x
forall a. Maybe a
Nothing))
{-# INLINE withParam #-}