-- | Structure of rings with explicit units. 
module Algebra.Structures.ExplicitUnits
  ( ExplicitUnits(..)
  , propUnit, isUnit, (%|), (~=)
  ) where 

import Algebra.Structures.IntegralDomain
import Algebra.Structures.GCDDomain

infix 5 %|
infix 4 ~=

-- | A ring has explicit units if there is a function that can test if an
-- element is invertible and if this is the case give the inverse. 
class IntegralDomain a => ExplicitUnits a where
  unit :: a -> Maybe a

propUnit :: (ExplicitUnits a, Eq a) => a -> Bool
propUnit a = case unit a of
  Just a' -> a <*> a' == one
  Nothing -> True

-- | An element is a unit if it is invertible. 
isUnit :: ExplicitUnits a => a -> Bool
isUnit = maybe False (const True) . unit

-- | Decidable units is sufficient to decide divisibility in GCD domains. 
(%|) :: (ExplicitUnits a, GCDDomain a) => a -> a -> Bool
a %| b = let (g,x,y) = gcd' a b
         in isUnit x

-- | Test for associatedness, i.e. a ~ b iff a | b /\\ b | a.
(~=) :: (ExplicitUnits a, GCDDomain a) => a -> a -> Bool
a ~= b = a %| b && b %| a