{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
module LAoP.Utils.Internal
(
Natural(..),
nat,
coerceNat,
coerceNat2,
coerceNat3,
List (..)
)
where
import Data.Coerce
import Data.Proxy
import Data.List
import Data.Maybe
import GHC.TypeLits
import Control.DeepSeq
import GHC.Generics
newtype Natural (start :: Nat) (end :: Nat) = Nat Int
deriving (Show, Read, Eq, Ord, NFData, Generic)
instance (KnownNat n, KnownNat m) => Num (Natural n m) where
(Nat a) + (Nat b) = nat @n @m (a + b)
(Nat a) - (Nat b) = nat @n @m (a - b)
(Nat a) * (Nat b) = nat @n @m (a * b)
abs (Nat a) = nat @n @m (abs a)
signum (Nat a) = nat @n @m (signum a)
fromInteger i = nat @n @m (fromInteger i)
nat :: forall n m . (KnownNat n, KnownNat m) => Int -> Natural n m
nat i =
let start = fromInteger (natVal (Proxy :: Proxy n))
end = fromInteger (natVal (Proxy :: Proxy m))
in if start <= i && i <= end
then Nat i
else error "Off limits"
coerceNat :: (Int -> Int -> Int) -> (Natural a a' -> Natural b b' -> Natural c c')
coerceNat = coerce
coerceNat2 :: ((Int, Int) -> Int -> Int) -> ((Natural a a', Natural b b') -> Natural c c' -> Natural d d')
coerceNat2 = coerce
coerceNat3 :: (Int -> Int -> a) -> (Natural b b' -> Natural c c' -> a)
coerceNat3 = coerce
instance (KnownNat n, KnownNat m) => Bounded (Natural n m) where
minBound = Nat $ fromInteger (natVal (Proxy :: Proxy n))
maxBound = Nat $ fromInteger (natVal (Proxy :: Proxy m))
instance (KnownNat n, KnownNat m) => Enum (Natural n m) where
toEnum i =
let start = fromInteger (natVal (Proxy :: Proxy n))
in nat (start + i)
fromEnum (Nat nat) =
let start = fromInteger (natVal (Proxy :: Proxy n))
end = fromInteger (natVal (Proxy :: Proxy m))
in if start <= nat && nat <= end
then nat - start
else error "Off limits"
instance
( Enum a,
Enum b,
Bounded b
) =>
Enum (a, b)
where
toEnum i =
let (listB :: [b]) = [minBound .. maxBound]
lengthB = length listB
fstI = div i lengthB
sndI = mod i lengthB
in (toEnum fstI, toEnum sndI)
fromEnum (a, b) =
let (listB :: [b]) = [minBound .. maxBound]
lengthB = length listB
fstI = fromEnum a
sndI = fromEnum b
in fstI * lengthB + sndI
instance
( Bounded a,
Bounded b
) => Bounded (Either a b)
where
minBound = Left (minBound :: a)
maxBound = Right (maxBound :: b)
instance
( Enum a,
Bounded a,
Enum b,
Bounded b
) => Enum (Either a b)
where
toEnum i =
let la = fmap Left ([minBound..maxBound] :: [a])
lb = fmap Right ([minBound..maxBound] :: [b])
in (la ++ lb) !! i
fromEnum (Left a) = fromEnum a
fromEnum (Right b) = fromEnum (maxBound :: a) + fromEnum b + 1
newtype List a = L [a]
deriving (Eq, Show, Read)
powerset :: [a] -> [[a]]
powerset [] = [[]]
powerset (x:xs) = powerset xs ++ [x:ps | ps <- powerset xs]
instance
( Enum a,
Bounded a
) => Bounded (List a)
where
minBound = L []
maxBound = L [minBound .. maxBound]
instance
( Bounded a,
Enum a,
Eq a
) => Enum (List a)
where
toEnum i =
let as = [minBound .. maxBound]
in L (powerset as !! i)
fromEnum (L []) = 0
fromEnum (L x) =
let as = [minBound .. maxBound]
in fromMaybe (error "Does not exist") $ elemIndex x (powerset as)