{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE UndecidableInstances #-}
module Grisette.Internal.Internal.Decl.Core.Data.Class.SafeDiv
( ArithException (..),
SafeDiv (..),
DivOr (..),
divOrZero,
modOrDividend,
quotOrZero,
remOrDividend,
divModOrZeroDividend,
quotRemOrZeroDividend,
)
where
import Control.Exception (ArithException (DivideByZero, Overflow, Underflow))
import Control.Monad.Except (MonadError)
import Grisette.Internal.Core.Data.Class.Mergeable (Mergeable)
import Grisette.Internal.Core.Data.Class.TryMerge
( TryMerge,
mrgSingle,
)
import Grisette.Lib.Data.Functor (mrgFmap)
class DivOr a where
divOr :: a -> a -> a -> a
modOr :: a -> a -> a -> a
divModOr :: (a, a) -> a -> a -> (a, a)
quotOr :: a -> a -> a -> a
remOr :: a -> a -> a -> a
quotRemOr :: (a, a) -> a -> a -> (a, a)
divOrZero :: (DivOr a, Num a) => a -> a -> a
divOrZero :: forall a. (DivOr a, Num a) => a -> a -> a
divOrZero a
l = a -> a -> a -> a
forall a. DivOr a => a -> a -> a -> a
divOr (a
l a -> a -> a
forall a. Num a => a -> a -> a
- a
l) a
l
{-# INLINE divOrZero #-}
modOrDividend :: (DivOr a, Num a) => a -> a -> a
modOrDividend :: forall a. (DivOr a, Num a) => a -> a -> a
modOrDividend a
l = a -> a -> a -> a
forall a. DivOr a => a -> a -> a -> a
modOr a
l a
l
{-# INLINE modOrDividend #-}
quotOrZero :: (DivOr a, Num a) => a -> a -> a
quotOrZero :: forall a. (DivOr a, Num a) => a -> a -> a
quotOrZero a
l = a -> a -> a -> a
forall a. DivOr a => a -> a -> a -> a
quotOr (a
l a -> a -> a
forall a. Num a => a -> a -> a
- a
l) a
l
{-# INLINE quotOrZero #-}
remOrDividend :: (DivOr a, Num a) => a -> a -> a
remOrDividend :: forall a. (DivOr a, Num a) => a -> a -> a
remOrDividend a
l = a -> a -> a -> a
forall a. DivOr a => a -> a -> a -> a
remOr a
l a
l
{-# INLINE remOrDividend #-}
divModOrZeroDividend :: (DivOr a, Num a) => a -> a -> (a, a)
divModOrZeroDividend :: forall a. (DivOr a, Num a) => a -> a -> (a, a)
divModOrZeroDividend a
l = (a, a) -> a -> a -> (a, a)
forall a. DivOr a => (a, a) -> a -> a -> (a, a)
divModOr (a
l a -> a -> a
forall a. Num a => a -> a -> a
- a
l, a
l) a
l
{-# INLINE divModOrZeroDividend #-}
quotRemOrZeroDividend :: (DivOr a, Num a) => a -> a -> (a, a)
quotRemOrZeroDividend :: forall a. (DivOr a, Num a) => a -> a -> (a, a)
quotRemOrZeroDividend a
l = (a, a) -> a -> a -> (a, a)
forall a. DivOr a => (a, a) -> a -> a -> (a, a)
quotRemOr (a
l a -> a -> a
forall a. Num a => a -> a -> a
- a
l, a
l) a
l
{-# INLINE quotRemOrZeroDividend #-}
class (MonadError e m, TryMerge m, Mergeable a, DivOr a) => SafeDiv e a m where
safeDiv :: a -> a -> m a
safeDiv a
l a
r = ((a, a) -> a) -> m (a, a) -> m a
forall (f :: * -> *) a b.
(TryMerge f, Mergeable a, Mergeable b, Functor f) =>
(a -> b) -> f a -> f b
mrgFmap (a, a) -> a
forall a b. (a, b) -> a
fst (m (a, a) -> m a) -> m (a, a) -> m a
forall a b. (a -> b) -> a -> b
$ a -> a -> m (a, a)
forall e a (m :: * -> *). SafeDiv e a m => a -> a -> m (a, a)
safeDivMod a
l a
r
{-# INLINE safeDiv #-}
safeMod :: a -> a -> m a
safeMod a
l a
r = ((a, a) -> a) -> m (a, a) -> m a
forall (f :: * -> *) a b.
(TryMerge f, Mergeable a, Mergeable b, Functor f) =>
(a -> b) -> f a -> f b
mrgFmap (a, a) -> a
forall a b. (a, b) -> b
snd (m (a, a) -> m a) -> m (a, a) -> m a
forall a b. (a -> b) -> a -> b
$ a -> a -> m (a, a)
forall e a (m :: * -> *). SafeDiv e a m => a -> a -> m (a, a)
safeDivMod a
l a
r
{-# INLINE safeMod #-}
safeDivMod :: a -> a -> m (a, a)
safeDivMod a
l a
r = do
d <- a -> a -> m a
forall e a (m :: * -> *). SafeDiv e a m => a -> a -> m a
safeDiv a
l a
r
m <- safeMod l r
mrgSingle (d, m)
{-# INLINE safeDivMod #-}
safeQuot :: a -> a -> m a
safeQuot a
l a
r = ((a, a) -> a) -> m (a, a) -> m a
forall (f :: * -> *) a b.
(TryMerge f, Mergeable a, Mergeable b, Functor f) =>
(a -> b) -> f a -> f b
mrgFmap (a, a) -> a
forall a b. (a, b) -> a
fst (m (a, a) -> m a) -> m (a, a) -> m a
forall a b. (a -> b) -> a -> b
$ a -> a -> m (a, a)
forall e a (m :: * -> *). SafeDiv e a m => a -> a -> m (a, a)
safeQuotRem a
l a
r
{-# INLINE safeQuot #-}
safeRem :: a -> a -> m a
safeRem a
l a
r = ((a, a) -> a) -> m (a, a) -> m a
forall (f :: * -> *) a b.
(TryMerge f, Mergeable a, Mergeable b, Functor f) =>
(a -> b) -> f a -> f b
mrgFmap (a, a) -> a
forall a b. (a, b) -> b
snd (m (a, a) -> m a) -> m (a, a) -> m a
forall a b. (a -> b) -> a -> b
$ a -> a -> m (a, a)
forall e a (m :: * -> *). SafeDiv e a m => a -> a -> m (a, a)
safeQuotRem a
l a
r
{-# INLINE safeRem #-}
safeQuotRem :: a -> a -> m (a, a)
safeQuotRem a
l a
r = do
q <- a -> a -> m a
forall e a (m :: * -> *). SafeDiv e a m => a -> a -> m a
safeQuot a
l a
r
m <- safeRem l r
mrgSingle (q, m)
{-# INLINE safeQuotRem #-}
{-# MINIMAL
((safeDiv, safeMod) | safeDivMod),
((safeQuot, safeRem) | safeQuotRem)
#-}