content: {-# 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
  
  