apply-unordered-1.0: src/Control/Apply/Positional.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE UndecidableInstances #-}
-- | FIXME
module Control.Apply.Positional
( applyN
, applyN'
, ApplyAt(ApplyAtResult)
, CheckArity
) where
import GHC.Exts (Constraint)
import Data.Proxy (Proxy(..))
import Data.Type.Nat (Nat(..), FromGHC)
import GHC.TypeLits (TypeError, ErrorMessage(..))
import qualified GHC.TypeLits as GHC
-- | FIXME: document
--
-- NOTE: Only usable via TypeApplication
applyN
:: forall (gn :: GHC.Nat) a f n.
( n ~ FromGHC gn
, CheckArity gn f n f
, ApplyAt n a f
)
=> f -> a -> ApplyAtResult n a f
applyN = applyN' (Proxy :: Proxy gn)
{-# INLINE applyN #-}
-- | FIXME: document
applyN'
:: forall (gn :: GHC.Nat) a f n.
( n ~ FromGHC gn
, CheckArity gn f n f
, ApplyAt n a f
)
=> Proxy gn -> f -> a -> ApplyAtResult n a f
applyN' _ = applyAtImpl (Proxy :: Proxy n)
{-# INLINE applyN' #-}
-- | Typeclass used to implement 'applyN'. The first type argument is
-- the number of arguments to skip before doing the application.
class ApplyAt (n :: Nat) a f where
type ApplyAtResult n a f
applyAtImpl
:: Proxy n
-> f
-> a
-> ApplyAtResult n a f
instance a ~ b => ApplyAt Z a (b -> r) where
type ApplyAtResult Z a (b -> r) = r
applyAtImpl _ f x = f x
{-# INLINE applyAtImpl #-}
instance ApplyAt n a r
=> ApplyAt (S n) a (b -> r) where
type ApplyAtResult (S n) a (b -> r) = b -> ApplyAtResult n a r
applyAtImpl _ f y = \x -> applyAtImpl (Proxy :: Proxy n) (f x) y
{-# INLINE applyAtImpl #-}
type family CheckArity (n0 :: GHC.Nat) f0 (n :: Nat) f :: Constraint where
CheckArity n0 f0 (S n) (_ -> r) = CheckArity n0 f0 n r
CheckArity n0 f0 Z (_ -> r) = ()
CheckArity n0 f0 (S n) r = TypeError (TooFewParametersMsg n0 f0)
CheckArity n0 f0 Z r = TypeError (TooFewParametersMsg n0 f0)
type TooFewParametersMsg (n :: GHC.Nat) f =
'Text "Cannot apply argument index " :<>: 'ShowType n :<>:
'Text " of a function of type" :$$:
'Text " " :<>: 'ShowType f :$$:
'Text "because it has too few arguments."