packages feed

i-0.1: hs/I/Natural.hs

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

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

module I.Natural () where

import Control.Monad
import Data.Bits
import Data.Constraint
import Data.Maybe
import Data.Proxy
import Data.Type.Ord
import Numeric.Natural (Natural)
import GHC.TypeNats qualified as N
import KindInteger (type (/=))
import Prelude hiding (min, max, div, succ)

import I.Internal

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

type instance MinL Natural = MinT Natural
type instance MaxR Natural = 'Nothing

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

instance forall l r.
  ( IntervalCtx    Natural l ('Just r)
  ) => Interval    Natural l ('Just r) where
  type IntervalCtx Natural l ('Just r) =
    ( N.KnownNat l
    , N.KnownNat r
    , MinT Natural <= l
    , l <= r )
  type MinI Natural l ('Just r) = l
  type MaxI Natural l ('Just r) = r
  inhabitant = min
  from = \x -> unsafest x <$ guard (l <= x && x <= r)
    where l = N.natVal (Proxy @l)
          r = N.natVal (Proxy @r)
  a `plus'` b = from (unwrap a + unwrap b)
  a `mult'` b = from (unwrap a * unwrap b)
  a `minus'` b = from =<< toIntegralSized (toInteger (unwrap a) -
                                           toInteger (unwrap b))
  a `div'` b = do guard (unwrap b /= 0)
                  (q, 0) <- pure $ divMod (unwrap a) (unwrap b)
                  from q

instance forall l.
  ( IntervalCtx    Natural l 'Nothing
  ) => Interval    Natural l 'Nothing where
  type IntervalCtx Natural l 'Nothing = (N.KnownNat l, MinT Natural <= l)
  type MinI Natural l 'Nothing = l
  inhabitant = min
  from = \x -> unsafest x <$ guard (l <= x)
    where l = N.natVal (Proxy @l)
  a `plus'` b = pure (a `plus` b)
  a `mult'` b = pure (a `mult` b)
  a `minus'` b = from =<< toIntegralSized (toInteger (unwrap a) -
                                           toInteger (unwrap b))
  a `div'` b = do guard (unwrap b /= 0)
                  (q, 0) <- pure $ divMod (unwrap a) (unwrap b)
                  from q

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

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

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

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

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

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

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

instance forall l r t.
  ( Interval    Natural l ('Just r)
  , KnownCtx    Natural l ('Just r) t
  ) => Known    Natural l ('Just r) t where
  type KnownCtx Natural l ('Just r) t = (N.KnownNat t, l <= t, t <= r)
  known' = unsafe . N.natVal

instance forall t l.
  ( Interval    Natural l 'Nothing
  , KnownCtx    Natural l 'Nothing t
  ) => Known    Natural l 'Nothing t where
  type KnownCtx Natural l 'Nothing t = (N.KnownNat t, l <= t)
  known' = unsafe . N.natVal

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

instance forall l r.
  ( Interval Natural l ('Just r)
  ) => With  Natural l ('Just r) where
  with x g = case N.someNatVal (unwrap x) of
    N.SomeNat (pt :: Proxy t) ->
      fromMaybe (error "I.with(Natural): impossible") $ do
        Dict <- leNatural @l @t
        Dict <- leNatural @t @r
        pure (g pt)

instance forall l.
  ( Interval Natural l 'Nothing
  ) => With  Natural l 'Nothing where
  with x g = case N.someNatVal (unwrap x) of
    N.SomeNat (pt :: Proxy t) ->
      fromMaybe (error "I.with(Natural): impossible") $ do
        Dict <- leNatural @l @t
        pure (g pt)

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

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

instance
  ( Interval    Natural l 'Nothing
  ) => Discrete Natural l 'Nothing where
  pred' i = unsafe (unwrap i - 1) <$ guard (min < i)
  succ' = pure . succ

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

instance
  ( Interval Natural l 'Nothing
  ) => Plus  Natural l 'Nothing where
  plus a b = unsafe (unwrap a + unwrap b)

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

instance
  ( Interval Natural l 'Nothing
  ) => Mult  Natural l 'Nothing where
  mult a b = unsafe (unwrap a * unwrap b)

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

instance
  ( Discrete Natural l 'Nothing
  ) => Succ  Natural l 'Nothing where
  succ i = unsafe (unwrap i + 1)

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

instance
  ( Interval Natural 0 r
  ) => Zero  Natural 0 r where
  zero = unsafe 0

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

instance
  ( Interval Natural l 'Nothing, l <= 1
  ) => One   Natural l 'Nothing where
  one = unsafe 1

instance
  ( Interval Natural l ('Just r), l <= 1, 1 <= r
  ) => One   Natural l ('Just r) where
  one = unsafe 1

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

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

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