fixed-vector-0.4.4.0: Data/Vector/Fixed/Internal/Arity.hs
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DeriveDataTypeable #-}
-- |
-- Type class for working with N-ary functions
module Data.Vector.Fixed.Internal.Arity (
-- * Type-level naturals
Z
, S
-- ** Synonyms for small numerals
, N1
, N2
, N3
, N4
, N5
, N6
-- * N-ary functions
, Fn
, Fun(..)
, Arity(..)
, apply
, applyM
) where
import Control.Applicative (Applicative(..))
import Data.Typeable (Typeable)
----------------------------------------------------------------
-- Naturals
----------------------------------------------------------------
-- | Type level zero
data Z deriving Typeable
-- | Successor of n
data S n deriving Typeable
type N1 = S Z
type N2 = S N1
type N3 = S N2
type N4 = S N3
type N5 = S N4
type N6 = S N5
----------------------------------------------------------------
-- N-ary functions
----------------------------------------------------------------
-- | Type family for n-ary functions.
type family Fn n a b
type instance Fn Z a b = b
type instance Fn (S n) a b = a -> Fn n a b
-- | Newtype wrapper which is used to make 'Fn' injective.
newtype Fun n a b = Fun { unFun :: Fn n a b }
instance Arity n => Functor (Fun n a) where
fmap (f :: b -> c) (Fun g0 :: Fun n a b)
= Fun $ accum
(\(T_fmap g) a -> T_fmap (g a))
(\(T_fmap x) -> f x)
(T_fmap g0 :: T_fmap a b n)
{-# INLINE fmap #-}
instance Arity n => Applicative (Fun n a) where
pure (x :: x) = Fun $ accum (\(T_pure r) (_::a) -> T_pure r)
(\(T_pure r) -> r)
(T_pure x :: T_pure x n)
(Fun f0 :: Fun n a (p -> q)) <*> (Fun g0 :: Fun n a p)
= Fun $ accum (\(T_ap f g) a -> T_ap (f a) (g a))
(\(T_ap f g) -> f g)
(T_ap f0 g0 :: T_ap a (p -> q) p n)
{-# INLINE pure #-}
{-# INLINE (<*>) #-}
newtype T_fmap a b n = T_fmap (Fn n a b)
data T_pure a n = T_pure a
data T_ap a b c n = T_ap (Fn n a b) (Fn n a c)
----------------------------------------------------------------
-- Generic operations of N-ary functions
----------------------------------------------------------------
-- | Type class for handling /n/-ary functions.
class Arity n where
-- | Left fold over /n/ elements exposed as n-ary function.
accum :: (forall k. t (S k) -> a -> t k) -- ^ Fold function
-> (t Z -> b) -- ^ Extract result of fold
-> t n -- ^ Initial value
-> Fn n a b -- ^ Reduction function
-- | Monadic left fold.
accumM :: Monad m
=> (forall k. t (S k) -> a -> m (t k)) -- ^ Fold function
-> (t Z -> m b) -- ^ Extract result of fold
-> m (t n) -- ^ Initial value
-> Fn n a (m b) -- ^ Reduction function
-- | Apply all parameters to the function.
applyFun :: (forall k. t (S k) -> (a, t k)) -- ^ Get value to apply to function
-> t n -- ^ Initial value
-> Fn n a b -- ^ N-ary function
-> (b, t Z)
-- | Monadic apply
applyFunM :: Monad m
=> (forall k. t (S k) -> m (a, t k)) -- ^ Get value to apply to function
-> t n -- ^ Initial value
-> Fn n a (m b) -- ^ N-ary function
-> m (b, t Z)
-- | Arity of function.
arity :: n -> Int
-- | Apply all parameters to the function.
apply :: Arity n
=> (forall k. t (S k) -> (a, t k)) -- ^ Get value to apply to function
-> t n -- ^ Initial value
-> Fn n a b -- ^ N-ary function
-> b
{-# INLINE apply #-}
apply step z f = fst $ applyFun step z f
-- | Apply all parameters to the function.
applyM :: (Arity n, Monad m)
=> (forall k. t (S k) -> m (a, t k)) -- ^ Get value to apply to function
-> t n -- ^ Initial value
-> Fn n a (m b) -- ^ N-ary function
-> m b
{-# INLINE applyM #-}
applyM step z f = do
(r,_) <- applyFunM step z f
return r
instance Arity Z where
accum _ g t = g t
accumM _ g t = g =<< t
applyFun _ t h = (h,t)
applyFunM _ t h = do r <- h
return (r,t)
arity _ = 0
{-# INLINE accum #-}
{-# INLINE accumM #-}
{-# INLINE applyFun #-}
{-# INLINE applyFunM #-}
{-# INLINE arity #-}
instance Arity n => Arity (S n) where
accum f g t = \a -> accum f g (f t a)
accumM f g t = \a -> accumM f g $ flip f a =<< t
applyFun f t h = case f t of (a,u) -> applyFun f u (h a)
applyFunM f t h = do (a,u) <- f t
applyFunM f u (h a)
arity _ = 1 + arity (undefined :: n)
{-# INLINE accum #-}
{-# INLINE accumM #-}
{-# INLINE applyFun #-}
{-# INLINE applyFunM #-}
{-# INLINE arity #-}