module Algebra.Structures.FieldOfFractions
( FieldOfFractions(..)
, toFieldOfFractions, fromFieldOfFractions
, reduce
) where
import Test.QuickCheck
import Algebra.Structures.Field
import Algebra.Structures.GCDDomain
newtype GCDDomain a => FieldOfFractions a = F (a,a)
instance (GCDDomain a, Show a, Eq a) => Show (FieldOfFractions a) where
show (F (a,b)) | b == one = show a
| otherwise = case show b of
('-':xs) -> "-" ++ show a ++ "/" ++ xs
xs -> show a ++ "/" ++ xs
instance (GCDDomain a, Eq a, Arbitrary a) => Arbitrary (FieldOfFractions a) where
arbitrary = do
a <- arbitrary
b <- arbitrary
if b == zero
then return $ F (a,one)
else return $ F (a,b)
instance (GCDDomain a, Eq a) => Eq (FieldOfFractions a) where
f == g = a <*> d == b <*> c
where
F (a,b) = reduce f
F (c,d) = reduce g
instance (GCDDomain a, Eq a) => Ring (FieldOfFractions a) where
(F (a,b)) <+> (F (c,d)) = reduce (F (a <*> d <+> c <*> b,b <*> d))
(F (a,b)) <*> (F (c,d)) = reduce (F (a <*> c,b <*> d))
neg (F (a,b)) = reduce (F (neg a,b))
one = toFieldOfFractions one
zero = toFieldOfFractions zero
instance (GCDDomain a, Eq a) => CommutativeRing (FieldOfFractions a)
instance (GCDDomain a, Eq a) => IntegralDomain (FieldOfFractions a)
instance (GCDDomain a, Eq a) => Field (FieldOfFractions a) where
inv (F (a,b)) | b /= zero && a /= zero = reduce $ F (b,a)
| otherwise = error "FieldOfFraction: Division by zero"
toFieldOfFractions :: GCDDomain a => a -> FieldOfFractions a
toFieldOfFractions a = F (a,one)
fromFieldOfFractions :: (GCDDomain a, Eq a) => FieldOfFractions a -> a
fromFieldOfFractions (F (a,b))
| b == one = a
| otherwise = error "FieldOfFractions: Can't extract value"
reduce :: (GCDDomain a, Eq a) => FieldOfFractions a -> FieldOfFractions a
reduce (F (a,b)) | b == zero = error "FieldOfFractions: Division by zero"
| a == zero = F (zero,one)
| otherwise = if g == one
then F (a,b)
else F (x,y)
where
(g,x,y) = gcd' a b
propReduce :: (GCDDomain a, Eq a) => FieldOfFractions a -> Property
propReduce f@(F (a,b)) = a /= zero && b /= zero ==> g == one
where
F (c,d) = reduce f
(g,_,_) = gcd' c d