{-# LANGUAGE DefaultSignatures #-}
module Numeric.Algebra.Unital.UnitNormalForm 
    (UnitNormalForm(..), normalize, leadingUnit) where

import Numeric.Algebra.Class
import Numeric.Algebra.Division
import Numeric.Algebra.Unital
import Numeric.Decidable.Units
import Numeric.Decidable.Associates
import Numeric.Decidable.Zero
import Numeric.Semiring.ZeroProduct
import Prelude(Integer,signum,abs,fst,snd,(.), otherwise)

class (DecidableUnits r, DecidableAssociates r) => UnitNormalForm r where
    -- prop> let (u,n) = splitUnit r
    --           (u',n') = splitUnit r' in
    --           isUnit u && isUnit u' &&
    --           u*n = r && u'*n' = r' &&
    --           (isAssociate r r' ==> n = n') &&
    --           splitUnit (r * r') = (u * u', n * n')
    splitUnit :: r -> (r,r)
    default splitUnit :: (Division r, ZeroProductSemiring r, DecidableZero r) => r -> (r,r)
    splitUnit x | isZero x = (one,zero)
                | otherwise = (x,one)

instance UnitNormalForm Integer where
  splitUnit 0 = (1, 0)
  splitUnit n = (signum n, abs n)
  {-# INLINE splitUnit #-}

normalize :: UnitNormalForm r => r -> r
normalize = snd . splitUnit

leadingUnit :: UnitNormalForm r => r -> r
leadingUnit = fst . splitUnit