{-# LANGUAGE TemplateHaskell #-}
{-|
    Module      :  Numeric.MixedType.Field
    Description :  Bottom-up typed division
    Copyright   :  (c) Michal Konecny
    License     :  BSD3

    Maintainer  :  mikkonecny@gmail.com
    Stability   :  experimental
    Portability :  portable

-}

module Numeric.MixedTypes.Field
(
  -- * Field
  CanAddSubMulDivCNBy, Field, OrderedField, OrderedCertainlyField
  -- * Division
  , CanDiv(..), CanDivBy, CanDivCNBy, CanDivSameType, CanDivCNSameType
  , CanRecip, CanRecipSameType, CanRecipCNSameType
  , (/), (/!), recip
  , powUsingMulRecip
  -- ** Tests
  , specCanDiv, specCanDivNotMixed
)
where

import Utils.TH.DeclForTypes

import Numeric.MixedTypes.PreludeHiding
import qualified Prelude as P
import Text.Printf

-- import qualified Data.List as List

import Test.Hspec
import Test.QuickCheck

import Numeric.CollectErrors
import Control.CollectErrors

import Numeric.MixedTypes.Literals
import Numeric.MixedTypes.Bool
import Numeric.MixedTypes.Eq
import Numeric.MixedTypes.Ord
-- import Numeric.MixedTypes.MinMaxAbs
-- import Numeric.MixedTypes.AddSub
import Numeric.MixedTypes.Ring

{----- Field -----}

type CanAddSubMulDivCNBy t s =
  (CanAddSubMulBy t s, CanAddSubMulBy (EnsureCN t) s, CanDivCNBy t s)

class
  (Ring t,
   CanDivCNSameType t, CanRecipCNSameType t,
   CanAddSubMulDivCNBy t Rational,
   CanAddSubMulDivCNBy t Integer,
   CanAddSubMulDivCNBy t Int
  )
  =>
  Field t

instance Field Rational
instance Field (CN Rational)

class
  (Field t, OrderedRing t, HasOrder t Rational, HasOrder (EnsureCN t) Rational)
  => OrderedField t

instance OrderedField Rational
instance OrderedField (CN Rational)

class
  (Field t, OrderedCertainlyRing t, HasOrderCertainly t Rational, HasOrderCertainly (EnsureCN t) Rational)
  => OrderedCertainlyField t

instance OrderedCertainlyField Rational
instance OrderedCertainlyField (CN Rational)

{---- Division -----}

{-|
  A replacement for Prelude's binary `P./`.  If @t1 = t2@ and @Fractional t1@,
  then one can use the default implementation to mirror Prelude's @/@.
-}
class CanDiv t1 t2 where
  type DivTypeNoCN t1 t2
  divideNoCN :: t1 -> t2 -> DivTypeNoCN t1 t2
  type DivType t1 t2
  type DivType t1 t2 = EnsureCN (DivTypeNoCN t1 t2)
  divide :: t1 -> t2 -> DivType t1 t2
  default divide ::
    (CanTestZero t2, CanEnsureCN (DivTypeNoCN t1 t2)
    , DivType t1 t2 ~ EnsureCN (DivTypeNoCN t1 t2))
    =>
    t1 -> t2 -> DivType t1 t2
  divide = (t1 -> t2 -> DivTypeNoCN t1 t2)
-> t1 -> t2 -> EnsureCN (DivTypeNoCN t1 t2)
forall t2 t3 t1.
(CanTestZero t2, CanEnsureCN t3) =>
(t1 -> t2 -> t3) -> t1 -> t2 -> EnsureCN t3
divideCN t1 -> t2 -> DivTypeNoCN t1 t2
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivTypeNoCN t1 t2
divideNoCN

divideCN ::
  (CanTestZero t2, CanEnsureCN t3)
  =>
  (t1 -> t2 -> t3) ->
  t1 -> t2 -> EnsureCN t3
divideCN :: (t1 -> t2 -> t3) -> t1 -> t2 -> EnsureCN t3
divideCN t1 -> t2 -> t3
unsafeDivide t1
a t2
b
  | t2 -> Bool
forall t. CanTestZero t => t -> Bool
isCertainlyZero t2
b = Maybe t3 -> NumError -> EnsureCN t3
forall v. CanEnsureCN v => Maybe v -> NumError -> EnsureCN v
noValueNumErrorCertainECN Maybe t3
sample_v NumError
DivByZero
  | t2 -> Bool
forall t. CanTestZero t => t -> Bool
isCertainlyNonZero t2
b = t3 -> EnsureCN t3
forall v. CanEnsureCN v => v -> EnsureCN v
ensureCN (t3 -> EnsureCN t3) -> t3 -> EnsureCN t3
forall a b. (a -> b) -> a -> b
$ t1
a t1 -> t2 -> t3
`unsafeDivide` t2
b
  | Bool
otherwise = Maybe t3 -> NumError -> EnsureCN t3
forall v. CanEnsureCN v => Maybe v -> NumError -> EnsureCN v
noValueNumErrorPotentialECN Maybe t3
sample_v NumError
DivByZero
  where
  sample_v :: Maybe t3
sample_v = t3 -> Maybe t3
forall a. a -> Maybe a
Just (t3 -> Maybe t3) -> t3 -> Maybe t3
forall a b. (a -> b) -> a -> b
$ t1 -> t2 -> t3
unsafeDivide t1
a t2
b

infixl 7  /,/!

(/) :: (CanDiv t1 t2) => t1 -> t2 -> DivType t1 t2
/ :: t1 -> t2 -> DivType t1 t2
(/) = t1 -> t2 -> DivType t1 t2
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivType t1 t2
divide

(/!) :: (CanDiv t1 t2) => t1 -> t2 -> DivTypeNoCN t1 t2
/! :: t1 -> t2 -> DivTypeNoCN t1 t2
(/!) = t1 -> t2 -> DivTypeNoCN t1 t2
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivTypeNoCN t1 t2
divideNoCN

type CanRecip t =
  (CanDiv Integer t)

type CanRecipSameType t =
  (CanDiv Integer t, DivType Integer t ~ t, DivTypeNoCN Integer t ~ t)

type CanRecipCNSameType t =
  (CanDiv Integer t, DivType Integer t ~ EnsureCN t, DivTypeNoCN Integer t ~ t
  ,CanEnsureCN t
  ,CanDiv Integer (EnsureCN t), DivType Integer (EnsureCN t) ~ EnsureCN t, DivTypeNoCN Integer (EnsureCN t) ~ (EnsureCN t))

recip :: (CanRecip t) => t -> DivType Integer t
recip :: t -> DivType Integer t
recip = Integer -> t -> DivType Integer t
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivType t1 t2
divide Integer
1

type CanDivBy t1 t2 =
  (CanDiv t1 t2, DivType t1 t2 ~ t1, DivTypeNoCN t1 t2 ~ t1)
type CanDivSameType t =
  CanDivBy t t

type CanDivCNBy t1 t2 =
  (CanDiv t1 t2, DivType t1 t2 ~ EnsureCN t1, DivTypeNoCN t1 t2 ~ t1
  , CanEnsureCN t1
  , CanDiv (EnsureCN t1) t2, DivType (EnsureCN t1) t2 ~ EnsureCN t1, DivTypeNoCN (EnsureCN t1) t2 ~ (EnsureCN t1))
type CanDivCNSameType t =
  (CanDivCNBy t t
  , CanDiv (EnsureCN t) (EnsureCN t), DivType (EnsureCN t) (EnsureCN t) ~ EnsureCN t, DivTypeNoCN (EnsureCN t) (EnsureCN t) ~ (EnsureCN t))

{-|
  HSpec properties that each implementation of CanDiv should satisfy.
 -}
specCanDiv ::
  (Show t1, Show t2, Show (DivType Integer (DivType Integer t1)),
   Show (DivType t1 t2), Show (DivType t1 t1),
   Show (MulType t1 (DivType t1 t2)), Arbitrary t1, Arbitrary t2,
   ConvertibleExactly Integer t1, ConvertibleExactly Integer t2,
   CanTestCertainly
     (EqCompareType (DivType Integer (DivType Integer t1)) t1),
   CanTestCertainly (EqCompareType (DivType t1 t2) t1),
   CanTestCertainly (EqCompareType (DivType t1 t1) t1),
   CanTestCertainly
     (EqCompareType (DivType t1 t2) (MulType t1 (DivType t1 t2))),
   HasEqAsymmetric (DivType Integer (DivType Integer t1)) t1,
   HasEqAsymmetric (DivType t1 t2) t1,
   HasEqAsymmetric (DivType t1 t2) (MulType t1 (DivType t1 t2)),
   HasEqAsymmetric (DivType t1 t1) t1, CanTestZero t1, CanTestZero t2,
   CanTestZero (DivType Integer t1),
   CanMulAsymmetric t1 (DivType t1 t2), CanDiv t1 t1, CanDiv t1 t2,
   CanDiv Integer t1, CanDiv Integer (DivType Integer t1))
  =>
  T t1 -> T t2 -> Spec
specCanDiv :: T t1 -> T t2 -> Spec
specCanDiv (T String
typeName1 :: T t1) (T String
typeName2 :: T t2) =
  String -> Spec -> Spec
forall a. HasCallStack => String -> SpecWith a -> SpecWith a
describe (String -> String -> String -> String
forall r. PrintfType r => String -> r
printf String
"CanDiv %s %s" String
typeName1 String
typeName2) (Spec -> Spec) -> Spec -> Spec
forall a b. (a -> b) -> a -> b
$ do
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"recip(recip x) = x" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t1 -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t1 -> Property) -> Property) -> (t1 -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t1
x :: t1) ->
        (t1 -> Bool
forall t. CanTestZero t => t -> Bool
isCertainlyNonZero t1
x Bool -> Bool -> AndOrType Bool Bool
forall a b. CanAndOrAsymmetric a b => a -> b -> AndOrType a b
&& DivType Integer t1 -> Bool
forall t. CanTestZero t => t -> Bool
isCertainlyNonZero (t1 -> DivType Integer t1
forall t. CanRecip t => t -> DivType Integer t
recip t1
x)) Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
          DivType Integer t1 -> DivType Integer (DivType Integer t1)
forall t. CanRecip t => t -> DivType Integer t
recip (t1 -> DivType Integer t1
forall t. CanRecip t => t -> DivType Integer t
recip t1
x) DivType Integer (DivType Integer t1) -> t1 -> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?==?$ t1
x
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"x/1 = x" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t1 -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t1 -> Property) -> Property) -> (t1 -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t1
x :: t1) -> let one :: t2
one = (Integer -> t2
forall t1 t2. ConvertibleExactly t1 t2 => t1 -> t2
convertExactly Integer
1 :: t2) in (t1
x t1 -> t2 -> DivType t1 t2
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivType t1 t2
/ t2
one) DivType t1 t2 -> t1 -> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?==?$ t1
x
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"x/x = 1" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t1 -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t1 -> Property) -> Property) -> (t1 -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t1
x :: t1) ->
        (t1 -> Bool
forall t. CanTestZero t => t -> Bool
isCertainlyNonZero t1
x) Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
          let one :: t1
one = (Integer -> t1
forall t1 t2. ConvertibleExactly t1 t2 => t1 -> t2
convertExactly Integer
1 :: t1) in (t1
x t1 -> t1 -> DivType t1 t1
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivType t1 t2
/ t1
x) DivType t1 t1 -> t1 -> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?==?$ t1
one
    String -> Property -> SpecWith (Arg Property)
forall a.
(HasCallStack, Example a) =>
String -> a -> SpecWith (Arg a)
it String
"x/y = x*(1/y)" (Property -> SpecWith (Arg Property))
-> Property -> SpecWith (Arg Property)
forall a b. (a -> b) -> a -> b
$ do
      (t1 -> t2 -> Property) -> Property
forall prop. Testable prop => prop -> Property
property ((t1 -> t2 -> Property) -> Property)
-> (t1 -> t2 -> Property) -> Property
forall a b. (a -> b) -> a -> b
$ \ (t1
x :: t1) (t2
y :: t2) ->
        (t2 -> Bool
forall t. CanTestZero t => t -> Bool
isCertainlyNonZero t2
y) Bool -> Property -> Property
forall prop. Testable prop => Bool -> prop -> Property
==>
          let one :: t1
one = (Integer -> t1
forall t1 t2. ConvertibleExactly t1 t2 => t1 -> t2
convertExactly Integer
1 :: t1) in (t1
x t1 -> t2 -> DivType t1 t2
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivType t1 t2
/ t2
y) DivType t1 t2 -> MulType t1 (DivType t1 t2) -> Property
forall a b.
(HasEqCertainlyAsymmetric a b, Show a, Show b) =>
a -> b -> Property
?==?$ t1
x t1 -> DivType t1 t2 -> MulType t1 (DivType t1 t2)
forall t1 t2. CanMulAsymmetric t1 t2 => t1 -> t2 -> MulType t1 t2
* (t1
onet1 -> t2 -> DivType t1 t2
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivType t1 t2
/t2
y)
  where
  infix 4 ?==?$
  (?==?$) :: (HasEqCertainlyAsymmetric a b, Show a, Show b) => a -> b -> Property
  ?==?$ :: a -> b -> Property
(?==?$) = String -> (a -> b -> Bool) -> a -> b -> Property
forall prop a b.
(Testable prop, Show a, Show b) =>
String -> (a -> b -> prop) -> a -> b -> Property
printArgsIfFails2 String
"?==?" a -> b -> Bool
forall a b. HasEqCertainlyAsymmetric a b => a -> b -> Bool
(?==?)

{-|
  HSpec properties that each implementation of CanDiv should satisfy.
 -}
specCanDivNotMixed ::
  (Show t, Show (DivType Integer (DivType Integer t)),
   Show (DivType t t), Show (MulType t (DivType t t)), Arbitrary t,
   ConvertibleExactly Integer t,
   CanTestCertainly
     (EqCompareType (DivType Integer (DivType Integer t)) t),
   CanTestCertainly (EqCompareType (DivType t t) t),
   CanTestCertainly
     (EqCompareType (DivType t t) (MulType t (DivType t t))),
   HasEqAsymmetric (DivType Integer (DivType Integer t)) t,
   HasEqAsymmetric (DivType t t) t,
   HasEqAsymmetric (DivType t t) (MulType t (DivType t t)),
   CanTestZero t, CanTestZero (DivType Integer t),
   CanMulAsymmetric t (DivType t t), CanDiv t t, CanDiv Integer t,
   CanDiv Integer (DivType Integer t))
  =>
  T t -> Spec
specCanDivNotMixed :: T t -> Spec
specCanDivNotMixed (T t
t :: T t) = T t -> T t -> Spec
forall t1 t2.
(Show t1, Show t2, Show (DivType Integer (DivType Integer t1)),
 Show (DivType t1 t2), Show (DivType t1 t1),
 Show (MulType t1 (DivType t1 t2)), Arbitrary t1, Arbitrary t2,
 ConvertibleExactly Integer t1, ConvertibleExactly Integer t2,
 CanTestCertainly
   (EqCompareType (DivType Integer (DivType Integer t1)) t1),
 CanTestCertainly (EqCompareType (DivType t1 t2) t1),
 CanTestCertainly (EqCompareType (DivType t1 t1) t1),
 CanTestCertainly
   (EqCompareType (DivType t1 t2) (MulType t1 (DivType t1 t2))),
 HasEqAsymmetric (DivType Integer (DivType Integer t1)) t1,
 HasEqAsymmetric (DivType t1 t2) t1,
 HasEqAsymmetric (DivType t1 t2) (MulType t1 (DivType t1 t2)),
 HasEqAsymmetric (DivType t1 t1) t1, CanTestZero t1, CanTestZero t2,
 CanTestZero (DivType Integer t1),
 CanMulAsymmetric t1 (DivType t1 t2), CanDiv t1 t1, CanDiv t1 t2,
 CanDiv Integer t1, CanDiv Integer (DivType Integer t1)) =>
T t1 -> T t2 -> Spec
specCanDiv T t
t T t
t

instance CanDiv Int Int where
  type DivTypeNoCN Int Int = Rational
  divideNoCN :: Int -> Int -> DivTypeNoCN Int Int
divideNoCN Int
a Int
b = Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
(P./) (Int -> Rational
forall t. CanBeRational t => t -> Rational
rational Int
a) (Int -> Rational
forall t. CanBeRational t => t -> Rational
rational Int
b)

instance CanDiv Integer Integer where
  type DivTypeNoCN Integer Integer = Rational
  divideNoCN :: Integer -> Integer -> DivTypeNoCN Integer Integer
divideNoCN Integer
a Integer
b = Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
(P./) (Integer -> Rational
forall t. CanBeRational t => t -> Rational
rational Integer
a) (Integer -> Rational
forall t. CanBeRational t => t -> Rational
rational Integer
b)
instance CanDiv Rational Rational where
  type DivTypeNoCN Rational Rational = Rational
  divideNoCN :: Rational -> Rational -> DivTypeNoCN Rational Rational
divideNoCN = Rational -> Rational -> DivTypeNoCN Rational Rational
forall a. Fractional a => a -> a -> a
(P./)

instance CanDiv Int Integer where
  type DivTypeNoCN Int Integer = Rational
  divideNoCN :: Int -> Integer -> DivTypeNoCN Int Integer
divideNoCN Int
a Integer
b = Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
(P./) (Int -> Rational
forall t. CanBeRational t => t -> Rational
rational Int
a) (Integer -> Rational
forall t. CanBeRational t => t -> Rational
rational Integer
b)
instance CanDiv Integer Int where
  type DivTypeNoCN Integer Int = Rational
  divideNoCN :: Integer -> Int -> DivTypeNoCN Integer Int
divideNoCN Integer
a Int
b = Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
(P./) (Integer -> Rational
forall t. CanBeRational t => t -> Rational
rational Integer
a) (Int -> Rational
forall t. CanBeRational t => t -> Rational
rational Int
b)

instance CanDiv Int Rational where
  type DivTypeNoCN Int Rational = Rational
  divideNoCN :: Int -> Rational -> DivTypeNoCN Int Rational
divideNoCN = (Rational -> Rational -> Rational) -> Int -> Rational -> Rational
forall a b c.
ConvertibleExactly a b =>
(b -> b -> c) -> a -> b -> c
convertFirst Rational -> Rational -> Rational
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivTypeNoCN t1 t2
divideNoCN
instance CanDiv Rational Int where
  type DivTypeNoCN Rational Int = Rational
  divideNoCN :: Rational -> Int -> DivTypeNoCN Rational Int
divideNoCN = (Rational -> Rational -> Rational) -> Rational -> Int -> Rational
forall b a c.
ConvertibleExactly b a =>
(a -> a -> c) -> a -> b -> c
convertSecond Rational -> Rational -> Rational
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivTypeNoCN t1 t2
divideNoCN

instance CanDiv Integer Rational where
  type DivTypeNoCN Integer Rational = Rational
  divideNoCN :: Integer -> Rational -> DivTypeNoCN Integer Rational
divideNoCN = (Rational -> Rational -> Rational)
-> Integer -> Rational -> Rational
forall a b c.
ConvertibleExactly a b =>
(b -> b -> c) -> a -> b -> c
convertFirst Rational -> Rational -> Rational
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivTypeNoCN t1 t2
divideNoCN
instance CanDiv Rational Integer where
  type DivTypeNoCN Rational Integer = Rational
  divideNoCN :: Rational -> Integer -> DivTypeNoCN Rational Integer
divideNoCN = (Rational -> Rational -> Rational)
-> Rational -> Integer -> Rational
forall b a c.
ConvertibleExactly b a =>
(a -> a -> c) -> a -> b -> c
convertSecond Rational -> Rational -> Rational
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivTypeNoCN t1 t2
divideNoCN

instance CanDiv Double Double where
  type DivTypeNoCN Double Double = Double
  divideNoCN :: Double -> Double -> DivTypeNoCN Double Double
divideNoCN = Double -> Double -> DivTypeNoCN Double Double
forall a. Fractional a => a -> a -> a
(P./)
  type DivType Double Double = Double
  divide :: Double -> Double -> DivType Double Double
divide = Double -> Double -> DivType Double Double
forall a. Fractional a => a -> a -> a
(P./)

$(declForTypes
  [[t| Integer |], [t| Int |], [t| Rational |]]
  (\ t -> [d|

    instance CanDiv $t Double where
      type DivType $t Double = Double
      divide n d = divide (double n) d
      type DivTypeNoCN $t Double = Double
      divideNoCN n d = divide (double n) d
    instance CanDiv Double $t where
      type DivType Double $t = Double
      divide d n = divide d (double n)
      type DivTypeNoCN Double $t = Double
      divideNoCN d n = divide d (double n)
  |]))

instance (CanDiv a b) => CanDiv [a] [b] where
  type DivTypeNoCN [a] [b] = [DivTypeNoCN a b]
  divideNoCN :: [a] -> [b] -> DivTypeNoCN [a] [b]
divideNoCN (a
x:[a]
xs) (b
y:[b]
ys) = (a -> b -> DivTypeNoCN a b
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivTypeNoCN t1 t2
divideNoCN a
x b
y) DivTypeNoCN a b -> [DivTypeNoCN a b] -> [DivTypeNoCN a b]
forall a. a -> [a] -> [a]
: ([a] -> [b] -> DivTypeNoCN [a] [b]
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivTypeNoCN t1 t2
divideNoCN [a]
xs [b]
ys)
  divideNoCN [a]
_ [b]
_ = []
  type DivType [a] [b] = [DivType a b]
  divide :: [a] -> [b] -> DivType [a] [b]
divide (a
x:[a]
xs) (b
y:[b]
ys) = (a -> b -> DivType a b
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivType t1 t2
divide a
x b
y) DivType a b -> [DivType a b] -> [DivType a b]
forall a. a -> [a] -> [a]
: ([a] -> [b] -> DivType [a] [b]
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivType t1 t2
divide [a]
xs [b]
ys)
  divide [a]
_ [b]
_ = []

instance (CanDiv a b) => CanDiv (Maybe a) (Maybe b) where
  type DivType (Maybe a) (Maybe b) = Maybe (DivType a b)
  divide :: Maybe a -> Maybe b -> DivType (Maybe a) (Maybe b)
divide (Just a
x) (Just b
y) = DivType a b -> Maybe (DivType a b)
forall a. a -> Maybe a
Just (a -> b -> DivType a b
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivType t1 t2
divide a
x b
y)
  divide Maybe a
_ Maybe b
_ = DivType (Maybe a) (Maybe b)
forall a. Maybe a
Nothing
  type DivTypeNoCN (Maybe a) (Maybe b) = Maybe (DivTypeNoCN a b)
  divideNoCN :: Maybe a -> Maybe b -> DivTypeNoCN (Maybe a) (Maybe b)
divideNoCN (Just a
x) (Just b
y) = DivTypeNoCN a b -> Maybe (DivTypeNoCN a b)
forall a. a -> Maybe a
Just (a -> b -> DivTypeNoCN a b
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivTypeNoCN t1 t2
divideNoCN a
x b
y)
  divideNoCN Maybe a
_ Maybe b
_ = DivTypeNoCN (Maybe a) (Maybe b)
forall a. Maybe a
Nothing

instance
  (CanDiv a b
  , CanEnsureCE es a, CanEnsureCE es b
  , CanEnsureCE es (DivType a b)
  , CanEnsureCE es (DivTypeNoCN a b)
  , SuitableForCE es)
  =>
  CanDiv (CollectErrors es a) (CollectErrors es  b)
  where
  type DivType (CollectErrors es a) (CollectErrors es b) =
    EnsureCE es (DivType a b)
  divide :: CollectErrors es a
-> CollectErrors es b
-> DivType (CollectErrors es a) (CollectErrors es b)
divide = (a -> b -> DivType a b)
-> CollectErrors es a
-> CollectErrors es b
-> EnsureCE es (DivType a b)
forall es a b c.
(SuitableForCE es, CanEnsureCE es a, CanEnsureCE es b,
 CanEnsureCE es c) =>
(a -> b -> c)
-> CollectErrors es a -> CollectErrors es b -> EnsureCE es c
lift2CE a -> b -> DivType a b
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivType t1 t2
divide
  type DivTypeNoCN (CollectErrors es a) (CollectErrors es b) =
    EnsureCE es (DivTypeNoCN a b)
  divideNoCN :: CollectErrors es a
-> CollectErrors es b
-> DivTypeNoCN (CollectErrors es a) (CollectErrors es b)
divideNoCN = (a -> b -> DivTypeNoCN a b)
-> CollectErrors es a
-> CollectErrors es b
-> EnsureCE es (DivTypeNoCN a b)
forall es a b c.
(SuitableForCE es, CanEnsureCE es a, CanEnsureCE es b,
 CanEnsureCE es c) =>
(a -> b -> c)
-> CollectErrors es a -> CollectErrors es b -> EnsureCE es c
lift2CE a -> b -> DivTypeNoCN a b
forall t1 t2. CanDiv t1 t2 => t1 -> t2 -> DivTypeNoCN t1 t2
divideNoCN

powUsingMulRecip ::
  (CanBeInteger e,
   CanRecipCNSameType t, CanMulSameType t, CanEnsureCN t)
   =>
   t -> t -> e -> EnsureCN t
powUsingMulRecip :: t -> t -> e -> EnsureCN t
powUsingMulRecip t
one t
x e
nPre
  | Integer
n Integer -> Integer -> OrderCompareType Integer Integer
forall a b.
HasOrderAsymmetric a b =>
a -> b -> OrderCompareType a b
< Integer
0 = t -> DivType Integer t
forall t. CanRecip t => t -> DivType Integer t
recip (t -> DivType Integer t) -> t -> DivType Integer t
forall a b. (a -> b) -> a -> b
$ t -> t -> Integer -> t
forall e t. (CanBeInteger e, CanMulSameType t) => t -> t -> e -> t
powUsingMul t
one t
x (Integer -> NegType Integer
forall t. CanNeg t => t -> NegType t
negate Integer
n)
  | Bool
otherwise = t -> EnsureCN t
forall v. CanEnsureCN v => v -> EnsureCN v
ensureCN (t -> EnsureCN t) -> t -> EnsureCN t
forall a b. (a -> b) -> a -> b
$ t -> t -> Integer -> t
forall e t. (CanBeInteger e, CanMulSameType t) => t -> t -> e -> t
powUsingMul t
one t
x Integer
n
  where
  n :: Integer
n = e -> Integer
forall t. CanBeInteger t => t -> Integer
integer e
nPre

$(declForTypes
  [[t| Integer |], [t| Int |], [t| Rational |], [t| Double |]]
  (\ t -> [d|

    instance
      (CanDiv $t b
      , CanEnsureCE es b
      , CanEnsureCE es (DivType $t b)
      , CanEnsureCE es (DivTypeNoCN $t b)
      , SuitableForCE es)
      =>
      CanDiv $t (CollectErrors es  b)
      where
      type DivType $t (CollectErrors es  b) =
        EnsureCE es (DivType $t b)
      divide = lift2TLCE divide
      type DivTypeNoCN $t (CollectErrors es  b) =
        EnsureCE es (DivTypeNoCN $t b)
      divideNoCN = lift2TLCE divideNoCN

    instance
      (CanDiv a $t
      , CanEnsureCE es a
      , CanEnsureCE es (DivType a $t)
      , CanEnsureCE es (DivTypeNoCN a $t)
      , SuitableForCE es)
      =>
      CanDiv (CollectErrors es a) $t
      where
      type DivType (CollectErrors es  a) $t =
        EnsureCE es (DivType a $t)
      divide = lift2TCE divide
      type DivTypeNoCN (CollectErrors es  a) $t =
        EnsureCE es (DivTypeNoCN a $t)
      divideNoCN = lift2TCE divideNoCN
  |]))