module NumericPrelude.Elementwise where

import Control.Applicative (Applicative(pure, (<*>)), )

{- |
A reader monad for the special purpose
of defining instances of certain operations on tuples and records.
It does not add any new functionality to the common Reader monad,
but it restricts the functions to the required ones
and exports them from one module.
That is you do not have to import
both Control.Monad.Trans.Reader and Control.Applicative.
The type also tells the user, for what the Reader monad is used.
We can more easily replace or extend the implementation when needed.
-}
newtype T v a = Cons {run :: v -> a}

{-# INLINE with #-}
with :: a -> T v a
with e = Cons $ \ _v -> e

{-# INLINE element #-}
element :: (v -> a) -> T v a
element = Cons


{-# INLINE run2 #-}
run2 :: T (x,y) a -> x -> y -> a
run2 = curry . run

{-# INLINE run3 #-}
run3 :: T (x,y,z) a -> x -> y -> z -> a
run3 e x y z = run e (x,y,z)

{-# INLINE run4 #-}
run4 :: T (x,y,z,w) a -> x -> y -> z -> w -> a
run4 e x y z w = run e (x,y,z,w)

{-# INLINE run5 #-}
run5 :: T (x,y,z,u,w) a -> x -> y -> z -> u -> w -> a
run5 e x y z u w = run e (x,y,z,u,w)


instance Functor (T v) where
   {-# INLINE fmap #-}
   fmap f (Cons e) =
      Cons $ \v -> f $ e v

instance Applicative (T v) where
   {-# INLINE pure #-}
   {-# INLINE (<*>) #-}
   pure = with
   Cons f <*> Cons e =
      Cons $ \v -> f v $ e v