{-# LANGUAGE CPP                        #-}
{-# LANGUAGE Safe                       #-}
{-# LANGUAGE PolyKinds                  #-}
{-# LANGUAGE ConstraintKinds            #-}
{-# LANGUAGE DefaultSignatures          #-}
{-# LANGUAGE DeriveFunctor              #-}
{-# LANGUAGE DeriveGeneric              #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE FlexibleInstances          #-}
{-# LANGUAGE TypeOperators              #-}

module Data.Semifield (
  -- * Semifields
    type SemifieldLaw, Semifield
  , anan, pinf
  , (/), (\\)
  , recip
  -- * Fields
  , type FieldLaw, Field, Real
  , ninf
  , (^^)
) where

import safe Data.Fixed
import safe Data.Semiring
import safe GHC.Real hiding (Real, Fractional(..), (^^), (^), div)
import safe Numeric.Natural
import safe Foreign.C.Types (CFloat(..),CDouble(..))

import Prelude (Monoid(..), Integer, Float, Double, ($))

-------------------------------------------------------------------------------
-- Semifields
-------------------------------------------------------------------------------

type SemifieldLaw a = ((Additive-Monoid) a, (Multiplicative-Group) a)

-- | A semifield, near-field, or division ring.
--
-- Instances needn't have commutative multiplication or additive inverses,
-- however addition must be commutative, and addition and multiplication must 
-- be associative as usual.
--
-- See also the wikipedia definitions of:
--
-- * < https://en.wikipedia.org/wiki/Semifield semifield >
-- * < https://en.wikipedia.org/wiki/Near-field_(mathematics) near-field >
-- * < https://en.wikipedia.org/wiki/Division_ring division ring >
-- 
class (Semiring a, SemifieldLaw a) => Semifield a

-- | The /NaN/ value of the semifield.
--
-- @ 'anan' = 'zero' '/' 'zero' @
--
anan :: Semifield a => a
anan = zero / zero
{-# INLINE anan #-}

-- | The positive infinity of the semifield.
--
-- @ 'pinf' = 'one' '/' 'zero' @
--
pinf :: Semifield a => a
pinf = one / zero
{-# INLINE pinf #-}

infixl 7 \\, /

-- | Reciprocal of a multiplicative group element.
--
-- @ 
-- x '/' y = x '*' 'recip' y
-- x '\\' y = 'recip' x '*' y
-- @
--
-- >>> recip (3 :+ 4) :: Complex Rational
-- 3 % 25 :+ (-4) % 25
-- >>> recip (3 :+ 4) :: Complex Double
-- 0.12 :+ (-0.16)
-- >>> recip (3 :+ 4) :: Complex Pico
-- 0.120000000000 :+ -0.160000000000
-- 
recip :: (Multiplicative-Group) a => a -> a
recip a = one / a
{-# INLINE recip #-}

-- | Right division by a multiplicative group element.
--
(/) :: (Multiplicative-Group) a => a -> a -> a
a / b = unMultiplicative (Multiplicative a << Multiplicative b)
{-# INLINE (/) #-}

-- | Left division by a multiplicative group element.
--
-- When '*' is commutative we must have:
--
-- @ x '\\' y = y '/' x @
--
(\\) :: (Multiplicative-Group) a => a -> a -> a
(\\) x y = recip x * y

-------------------------------------------------------------------------------
-- Fields
-------------------------------------------------------------------------------

type FieldLaw a = ((Additive-Group) a, (Multiplicative-Group) a)

-- | A < https://en.wikipedia.org/wiki/Field_(mathematics) field >.
--
class (Ring a, Semifield a, FieldLaw a) => Field a

-- | A type modeling the real numbers.
--
class Field a => Real a

-- | The 'one' '/' 'zero' value of the field.
--
-- @ 'ninf' = 'negate' 'one' '/' 'zero' @
--
ninf :: Field a => a
ninf = negate one / zero
{-# INLINE ninf #-}

infixr 8 ^^

-- | Integral power of a multiplicative group element.
--
-- @ 'one' '==' a '^^' 0 @
--
-- >>> 8 ^^ 0 :: Double
-- 1.0
-- >>> 8 ^^ 0 :: Pico
-- 1.000000000000
--
(^^) :: (Multiplicative-Group) a => a -> Integer -> a
a ^^ n = unMultiplicative $ greplicate n (Multiplicative a)

-------------------------------------------------------------------------------
-- Instances
-------------------------------------------------------------------------------

instance Semifield ()
instance Semifield (Ratio Natural)
instance Semifield Rational

instance Semifield Uni
instance Semifield Deci
instance Semifield Centi
instance Semifield Milli
instance Semifield Micro
instance Semifield Nano
instance Semifield Pico

instance Semifield Float
instance Semifield Double
instance Semifield CFloat
instance Semifield CDouble

--instance Field a => Semifield (Complex a)


instance Field ()
instance Field Rational

instance Field Uni
instance Field Deci
instance Field Centi
instance Field Milli
instance Field Micro
instance Field Nano
instance Field Pico

instance Field Float
instance Field Double
instance Field CFloat
instance Field CDouble

--instance Field a => Field (Complex a)



instance Real Rational

instance Real Uni
instance Real Deci
instance Real Centi
instance Real Milli
instance Real Micro
instance Real Nano
instance Real Pico

instance Real Float
instance Real Double
instance Real CFloat
instance Real CDouble