packages feed

i-0.1: hs/I/Integer.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE UndecidableInstances #-}

{-# OPTIONS_GHC -Wno-orphans #-}
{-# OPTIONS_HADDOCK not-home #-}

module I.Integer () where

import Control.Monad
import Data.Constraint
import Data.Maybe
import Data.Proxy
import Data.Type.Ord
import KindInteger qualified as K
import KindInteger (type (/=))
import Prelude hiding (min, max, div, succ, pred)
import Prelude qualified as P

import I.Internal

--------------------------------------------------------------------------------

type instance MinL P.Integer = 'Nothing
type instance MaxR P.Integer = 'Nothing

instance forall l r.
  ( IntervalCtx    P.Integer ('Just l) ('Just r)
  ) => Interval    P.Integer ('Just l) ('Just r) where
  type IntervalCtx P.Integer ('Just l) ('Just r) =
    (K.KnownInteger l, K.KnownInteger r, l <= r)
  type MinI P.Integer ('Just l) ('Just r) = l
  type MaxI P.Integer ('Just l) ('Just r) = r
  inhabitant = min
  from = \x -> unsafest x <$ guard (l <= x && x <= r)
    where l = K.integerVal (Proxy @l)
          r = K.integerVal (Proxy @r)
  negate' = from . P.negate . unwrap
  a `plus'` b = from (unwrap a + unwrap b)
  a `mult'` b = from (unwrap a * unwrap b)
  a `minus'` b = from (unwrap a - unwrap b)
  a `div'` b = do guard (unwrap b /= 0)
                  let (q, m) = divMod (unwrap a) (unwrap b)
                  guard (m == 0)
                  from q

instance forall l.
  ( IntervalCtx    P.Integer ('Just l) 'Nothing
  ) => Interval    P.Integer ('Just l) 'Nothing where
  type IntervalCtx P.Integer ('Just l) 'Nothing = K.KnownInteger l
  type MinI P.Integer ('Just l) 'Nothing = l
  inhabitant = min
  from = \x -> unsafest x <$ guard (l <= x)
    where l = K.integerVal (Proxy @l)
  negate' = from . P.negate . unwrap
  a `plus'` b = from (unwrap a + unwrap b)
  a `mult'` b = from (unwrap a * unwrap b)
  a `minus'` b = from (unwrap a - unwrap b)
  a `div'` b = do guard (unwrap b /= 0)
                  let (q, m) = divMod (unwrap a) (unwrap b)
                  guard (m == 0)
                  from q

instance forall r.
  ( IntervalCtx    P.Integer 'Nothing ('Just r)
  ) => Interval    P.Integer 'Nothing ('Just r) where
  type IntervalCtx P.Integer 'Nothing ('Just r) = K.KnownInteger r
  type MaxI P.Integer 'Nothing ('Just r) = r
  inhabitant = max
  from = \x -> unsafest x <$ guard (x <= r)
    where r = K.integerVal (Proxy @r)
  negate' = from . P.negate . unwrap
  a `plus'` b = from (unwrap a + unwrap b)
  a `mult'` b = from (unwrap a * unwrap b)
  a `minus'` b = from (unwrap a - unwrap b)
  a `div'` b = do guard (unwrap b /= 0)
                  let (q, m) = divMod (unwrap a) (unwrap b)
                  guard (m == 0)
                  from q

instance Interval P.Integer 'Nothing 'Nothing where
  inhabitant = zero
  from = pure . wrap
  negate' = pure . wrap . P.negate . unwrap
  a `plus'` b = pure (a `plus` b)
  a `mult'` b = pure (a `mult` b)
  a `minus'` b = pure (a `minus` b)
  a `div'` b = do guard (unwrap b /= 0)
                  let (q, m) = divMod (unwrap a) (unwrap b)
                  guard (m == 0)
                  from q

--------------------------------------------------------------------------------

instance
  ( Interval Integer ('Just l) ('Just r)
  ) => Clamp Integer ('Just l) ('Just r)

instance
  ( Interval Integer ('Just l) 'Nothing
  ) => Clamp Integer ('Just l) 'Nothing where
  clamp = \case
    x | x <= unwrap min_ -> min_
      | otherwise -> UnsafeI x
    where min_ = min

instance
  ( Interval Integer 'Nothing ('Just r)
  ) => Clamp Integer 'Nothing ('Just r) where
  clamp = \case
    x | x >= unwrap max_ -> max_
      | otherwise -> UnsafeI x
    where max_ = max

instance
  ( Interval Integer 'Nothing 'Nothing
  ) => Clamp Integer 'Nothing 'Nothing where
  clamp = UnsafeI

--------------------------------------------------------------------------------

instance
  ( lu <= ld
  , rd <= ru
  , Interval Integer ('Just ld) ('Just rd)
  , Interval Integer ('Just lu) ('Just ru)
  ) => Up    Integer ('Just ld) ('Just rd) ('Just lu) ('Just ru)

instance
  ( lu <= ld
  , Interval Integer ('Just ld) yrd
  , Interval Integer ('Just lu) 'Nothing
  ) => Up    Integer ('Just ld) yrd ('Just lu) 'Nothing

instance
  ( rd <= ru
  , Interval Integer yld ('Just rd)
  , Interval Integer 'Nothing ('Just ru)
  ) => Up    Integer yld ('Just rd) 'Nothing ('Just ru)

instance
  ( Interval Integer yld yrd
  , Interval Integer 'Nothing 'Nothing )
  => Up Integer yld yrd 'Nothing 'Nothing

--------------------------------------------------------------------------------

instance forall l r t.
  ( Interval    P.Integer ('Just l) ('Just r)
  , KnownCtx    P.Integer ('Just l) ('Just r) t
  ) => Known    P.Integer ('Just l) ('Just r) t where
  type KnownCtx P.Integer ('Just l) ('Just r) t =
    (K.KnownInteger t, l <= t, t <= r)
  known' = UnsafeI . K.integerVal

instance forall t l.
  ( Interval    P.Integer ('Just l) 'Nothing
  , KnownCtx    P.Integer ('Just l) 'Nothing t
  ) => Known    P.Integer ('Just l) 'Nothing t where
  type KnownCtx P.Integer ('Just l) 'Nothing t = (K.KnownInteger t, l <= t)
  known' = UnsafeI . K.integerVal

instance forall t r.
  ( Interval    P.Integer 'Nothing ('Just r)
  , KnownCtx    P.Integer 'Nothing ('Just r) t
  ) => Known    P.Integer 'Nothing ('Just r) t where
  type KnownCtx P.Integer 'Nothing ('Just r) t = (K.KnownInteger t, t <= r)
  known' = UnsafeI . K.integerVal

instance forall t.
  ( KnownCtx    P.Integer 'Nothing 'Nothing t
  ) => Known    P.Integer 'Nothing 'Nothing t where
  type KnownCtx P.Integer 'Nothing 'Nothing t = K.KnownInteger t
  known' = UnsafeI . K.integerVal

--------------------------------------------------------------------------------

instance forall l r.
  ( Interval P.Integer ('Just l) ('Just r)
  ) => With  P.Integer ('Just l) ('Just r) where
  with x g = case K.someIntegerVal (unwrap x) of
    K.SomeInteger (pt :: Proxy t) ->
      fromMaybe (error "I.with(Integer): impossible") $ do
        Dict <- leInteger @l @t
        Dict <- leInteger @t @r
        pure (g pt)

instance forall l.
  ( Interval P.Integer ('Just l) 'Nothing
  ) => With  P.Integer ('Just l) 'Nothing where
  with x g = case K.someIntegerVal (unwrap x) of
    K.SomeInteger (pt :: Proxy t) ->
      fromMaybe (error "I.with(Integer): impossible") $ do
        Dict <- leInteger @l @t
        pure (g pt)

instance forall r.
  ( Interval P.Integer 'Nothing ('Just r)
  ) => With  P.Integer 'Nothing ('Just r) where
  with x g = case K.someIntegerVal (unwrap x) of
    K.SomeInteger (pt :: Proxy t) ->
      fromMaybe (error "I.with(Integer): impossible") $ do
        Dict <- leInteger @t @r
        pure (g pt)

instance With P.Integer 'Nothing 'Nothing where
  with x g = case K.someIntegerVal (unwrap x) of
    K.SomeInteger (pt :: Proxy t) -> g pt

--------------------------------------------------------------------------------

instance
  ( Interval    P.Integer ('Just l) ('Just r), l /= r
  ) => Discrete P.Integer ('Just l) ('Just r) where
  pred' i = UnsafeI (unwrap i - 1) <$ guard (min < i)
  succ' i = UnsafeI (unwrap i + 1) <$ guard (i < max)

instance
  ( Interval    P.Integer ('Just l) 'Nothing
  ) => Discrete P.Integer ('Just l) 'Nothing where
  pred' i = UnsafeI (unwrap i - 1) <$ guard (min < i)
  succ' = pure . succ

instance
  ( Interval    P.Integer 'Nothing ('Just r)
  ) => Discrete P.Integer 'Nothing ('Just r) where
  pred' = pure . pred
  succ' i = UnsafeI (unwrap i + 1) <$ guard (i < max)

instance Discrete P.Integer 'Nothing 'Nothing where
  pred'  = pure . pred
  succ'  = pure . succ

--------------------------------------------------------------------------------

instance
  ( Discrete P.Integer 'Nothing r
  ) => Pred  P.Integer 'Nothing r where
  pred i = UnsafeI (unwrap i - 1)

--------------------------------------------------------------------------------

instance
  ( Discrete P.Integer l 'Nothing
  ) => Succ  P.Integer l 'Nothing where
  succ i = UnsafeI (unwrap i + 1)

--------------------------------------------------------------------------------

instance
  ( Interval P.Integer ('Just l) 'Nothing, K.P 0 <= l
  ) => Plus  P.Integer ('Just l) 'Nothing where
  a `plus` b = UnsafeI (unwrap a + unwrap b)

instance
  ( Interval P.Integer 'Nothing ('Just r), r <= K.P 0
  ) => Plus  P.Integer 'Nothing ('Just r) where
  a `plus` b = UnsafeI (unwrap a + unwrap b)

instance Plus P.Integer 'Nothing 'Nothing where
  a `plus` b = UnsafeI (unwrap a + unwrap b)

--------------------------------------------------------------------------------

instance
  ( Interval P.Integer ('Just l) 'Nothing, K.P 0 <= l
  ) => Mult P.Integer ('Just l) 'Nothing where
  a `mult` b = UnsafeI (unwrap a * unwrap b)

instance Mult P.Integer 'Nothing 'Nothing where
  a `mult` b = UnsafeI (unwrap a * unwrap b)

--------------------------------------------------------------------------------

instance Minus P.Integer 'Nothing 'Nothing where
  a `minus` b = UnsafeI (unwrap a - unwrap b)

--------------------------------------------------------------------------------

instance
  ( Interval P.Integer ('Just l) ('Just r), l <= K.P 0, K.P 0 <= r
  ) => Zero  P.Integer ('Just l) ('Just r) where
  zero = UnsafeI 0

instance
  ( Interval P.Integer ('Just l) 'Nothing, l <= K.P 0
  ) => Zero  P.Integer ('Just l) 'Nothing where
  zero = UnsafeI 0

instance
  ( Interval P.Integer 'Nothing ('Just r), K.P 0 <= r
  ) => Zero  P.Integer 'Nothing ('Just r) where
  zero = UnsafeI 0

instance Zero P.Integer 'Nothing 'Nothing where
  zero = UnsafeI 0

--------------------------------------------------------------------------------

instance
  ( Interval P.Integer ('Just l) ('Just r), l <= K.P 1, K.P 1 <= r
  ) => One   P.Integer ('Just l) ('Just r) where
  one = UnsafeI 1

instance
  ( Interval P.Integer ('Just l) 'Nothing, l <= K.P 1
  ) => One   P.Integer ('Just l) 'Nothing where
  one = UnsafeI 1

instance
  ( Interval P.Integer 'Nothing ('Just r), K.P 1 <= r
  ) => One   P.Integer 'Nothing ('Just r) where
  one = UnsafeI 1

instance One P.Integer 'Nothing 'Nothing where
  one = UnsafeI 1

--------------------------------------------------------------------------------

instance
  ( Zero      P.Integer ('Just l) ('Just r), l K.== K.Negate r
  ) => Negate P.Integer ('Just l) ('Just r) where
  negate = UnsafeI . P.negate . unwrap

instance Negate P.Integer 'Nothing 'Nothing where
  negate = UnsafeI . P.negate . unwrap

--------------------------------------------------------------------------------

instance
  ( Interval Integer ('Just l) ('Just r)
  ) => Shove Integer ('Just l) ('Just r) where
  shove = \x -> unsafe $ mod x (r - l + 1) + l
    where l = unwrap (min @Integer @('Just l) @('Just r))
          r = unwrap (max @Integer @('Just l) @('Just r))

instance
  ( Interval Integer ('Just l) 'Nothing
  ) => Shove Integer ('Just l) 'Nothing where
  shove = \x -> unsafe $ if x < l then l + (l - x) else x
    where l = unwrap (min @Integer @('Just l) @'Nothing)

instance
  ( Interval Integer 'Nothing ('Just r)
  ) => Shove Integer 'Nothing ('Just r) where
  shove = \x -> unsafe $ if x > r then r - (x - r) else x
    where r = unwrap (max @Integer @'Nothing @('Just r))

instance
  ( Interval Integer 'Nothing 'Nothing
  ) => Shove Integer 'Nothing 'Nothing where
  shove = wrap