{-
	Copyright (C) 2011 Dr. Alistair Ward

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
-}
{- |
 [@AUTHOR@]	Dr. Alistair Ward

 [@DESCRIPTION@]

	* Describes a simple numeric type, designed to contain an /exponential/ number.

	* <https://en.wikipedia.org/wiki/Exponentiation>.
-}

module Factory.Data.Exponential(
-- * Types
-- ** Type-synonyms
	Exponential,
-- * Functions
	evaluate,
	invert,
-- ** Accessors
	getBase,
	getExponent,
-- ** Constructor
	rightIdentity,
-- ** Operators
	(<^),
	(=~)
) where

import qualified	Control.Arrow

infix 4 =~	-- Same as (==).
infixr 8 <^	-- Same as (^).

-- | Describes an /exponential/, in terms of its /base/ and /exponent/.
type Exponential base exponent	= (base, exponent)

-- | Accessor.
{-# INLINE getBase #-}
getBase :: Exponential base exponent -> base
getBase :: Exponential base exponent -> base
getBase	= Exponential base exponent -> base
forall a b. (a, b) -> a
fst

-- | Accessor.
{-# INLINE getExponent #-}
getExponent :: Exponential base exponent -> exponent
getExponent :: Exponential base exponent -> exponent
getExponent	= Exponential base exponent -> exponent
forall a b. (a, b) -> b
snd

{- |
	* Construct an 'Exponential' merely raised to the 1st power.

	* The value of the resulting exponential is the same as specified 'base'; <https://en.wikipedia.org/wiki/Identity_element>.
-}
rightIdentity :: Num exponent => base -> Exponential base exponent
rightIdentity :: base -> Exponential base exponent
rightIdentity base
x	= (base
x, exponent
1)

-- | Evaluate the specified 'Exponential', returning the resulting number.
{-# INLINE evaluate #-}
evaluate :: (Num base, Integral exponent) => Exponential base exponent -> base
evaluate :: Exponential base exponent -> base
evaluate	= (base -> exponent -> base) -> Exponential base exponent -> base
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry base -> exponent -> base
forall a b. (Num a, Integral b) => a -> b -> a
(^)	-- CAVEAT: in this eta-reduced form, it'll only be inlined when called without arguments.

-- | True if the /bases/ are equal.
(=~) :: Eq base => Exponential base exponent -> Exponential base exponent -> Bool
(base
l, exponent
_) =~ :: Exponential base exponent -> Exponential base exponent -> Bool
=~ (base
r, exponent
_)	= base
l base -> base -> Bool
forall a. Eq a => a -> a -> Bool
== base
r

-- | Raise the specified 'Exponential' to a power.
(<^) :: Num exponent
	=> Exponential base exponent	-- ^ The operand.
	-> exponent			-- ^ The power to which the exponential is to be raised.
	-> Exponential base exponent	-- ^ The result.
(base
b, exponent
e) <^ :: Exponential base exponent -> exponent -> Exponential base exponent
<^ exponent
power	= (base
b, exponent
e exponent -> exponent -> exponent
forall a. Num a => a -> a -> a
* exponent
power)

-- | Invert the value, by negating the exponent.
invert :: Num exponent => Exponential base exponent -> Exponential base exponent
invert :: Exponential base exponent -> Exponential base exponent
invert	= (exponent -> exponent)
-> Exponential base exponent -> Exponential base exponent
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
Control.Arrow.second exponent -> exponent
forall a. Num a => a -> a
negate