{-# LANGUAGE CPP, GeneralizedNewtypeDeriving, ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving, TypeFamilies                     #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Algebra.Normed where
import AlgebraicPrelude

-- | Additional types for /normed/ types.
class (Ord (Norm a)) => Normed a where
  type Norm a
  norm :: a -> Norm a
  liftNorm :: Norm a -> a

#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 802
deriving instance Normed a => Normed (WrapNum a)
deriving instance Normed a => Normed (WrapFractional a)
deriving instance Normed a => Normed (WrapAlgebra a)
deriving instance Normed a => Normed (WrapIntegral a)

deriving instance Normed a => Normed (Add a)
deriving instance Normed a => Normed (Mult a)
#else
instance Normed a => Normed (WrapNum a) where
  type Norm (WrapNum a) = Norm a
  norm = norm . unwrapNum
  liftNorm = WrapNum . liftNorm

instance Normed a => Normed (WrapFractional a) where
  type Norm (WrapFractional a) = Norm a
  norm = norm . unwrapFractional
  liftNorm = WrapFractional . liftNorm

instance Normed a => Normed (WrapAlgebra a) where
  type Norm (WrapAlgebra a) = Norm a
  norm = norm . unwrapAlgebra
  liftNorm = WrapAlgebra . liftNorm

instance Normed a => Normed (WrapIntegral a) where
  type Norm (WrapIntegral a) = Norm a
  norm = norm . unwrapIntegral
  liftNorm = WrapIntegral . liftNorm

instance Normed a => Normed (Add a) where
  type Norm (Add a) = Norm a
  norm = norm . runAdd
  liftNorm = Add . liftNorm

instance Normed a => Normed (Mult a) where
  type Norm (Mult a) = Norm a
  norm = norm . runMult
  liftNorm = Mult . liftNorm
#endif

instance Normed Double where
  type Norm Double = Double
  norm :: Double -> Norm Double
norm = Double -> Norm Double
forall a. Num a => a -> a
abs
  liftNorm :: Norm Double -> Double
liftNorm = Norm Double -> Double
forall a. a -> a
id

instance Normed Int where
  type Norm Int = Int
  norm :: Int -> Norm Int
norm = Int -> Norm Int
forall a. Num a => a -> a
abs
  liftNorm :: Norm Int -> Int
liftNorm = Norm Int -> Int
forall a. a -> a
id

instance Normed Integer where
  type Norm Integer = Integer
  norm :: Integer -> Norm Integer
norm = Integer -> Norm Integer
forall a. Num a => a -> a
abs
  liftNorm :: Norm Integer -> Integer
liftNorm = Norm Integer -> Integer
forall a. a -> a
id

instance (Ord (Norm d), Euclidean d, Euclidean (Norm d), Normed d)
     =>  Normed (Fraction d) where
  type Norm (Fraction d) = Fraction (Norm d)
  norm :: Fraction d -> Norm (Fraction d)
norm Fraction d
f = d -> Norm d
forall a. Normed a => a -> Norm a
norm (Fraction d -> d
forall t. Fraction t -> t
numerator Fraction d
f) Norm d -> Norm d -> Fraction (Norm d)
forall d. GCDDomain d => d -> d -> Fraction d
% d -> Norm d
forall a. Normed a => a -> Norm a
norm (Fraction d -> d
forall t. Fraction t -> t
denominator Fraction d
f)
  liftNorm :: Norm (Fraction d) -> Fraction d
liftNorm Norm (Fraction d)
f = Norm d -> d
forall a. Normed a => Norm a -> a
liftNorm (Fraction (Norm d) -> Norm d
forall t. Fraction t -> t
numerator Fraction (Norm d)
Norm (Fraction d)
f) d -> d -> Fraction d
forall d. GCDDomain d => d -> d -> Fraction d
% Norm d -> d
forall a. Normed a => Norm a -> a
liftNorm (Fraction (Norm d) -> Norm d
forall t. Fraction t -> t
denominator Fraction (Norm d)
Norm (Fraction d)
f)

{-# ANN module "Hlint: ignore Unused LANGUAGE pragma" #-}