module Data.ANum (ANum(ANum), unANum) where

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


newtype ANum f n = ANum (f n)
  deriving (Show)

unANum :: ANum f n -> f n
unANum (ANum x) = x


instance (Functor f) => Functor (ANum f) where
  fmap f (ANum x) = ANum (fmap f x)

instance (Applicative f) => Applicative (ANum f) where
  pure x = ANum (pure x)
  (ANum f) <*> (ANum x) = ANum (f <*> x)


instance (Applicative f, Num n) => Num (ANum f n) where
  fromInteger = pure . fromInteger
  (*) = liftA2 (*)
  (+) = liftA2 (+)
  (-) = liftA2 (-)
  negate = liftA negate
  abs = liftA abs
  signum = liftA signum

instance (Applicative f, Fractional n) => Fractional (ANum f n) where
  (/) = liftA2 (/)
  recip = liftA recip
  fromRational = pure . fromRational

instance (Applicative f, Floating n) => Floating (ANum f n) where
  pi = pure pi
  exp = liftA exp
  sqrt = liftA sqrt
  log = liftA log
  (**) = liftA2 (**)
  logBase = liftA2 logBase
  sin = liftA sin
  tan = liftA tan
  cos = liftA cos
  asin = liftA asin
  atan = liftA atan
  acos = liftA acos
  sinh = liftA sinh
  tanh = liftA tanh
  cosh = liftA cosh
  asinh = liftA asinh
  atanh = liftA atanh
  acosh = liftA acosh