ox-arrays-0.2.0.0: src/Data/Array/Nested/Types.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE NoStarIsType #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-}
module Data.Array.Nested.Types (
-- * Reasoning helpers
subst1, subst2,
-- * Reified evidence of a type class
Dict(..),
-- * Type-level naturals
pattern SZ, pattern SS,
fromSNat', sameNat',
snatPlus, snatMinus, snatMul,
snatSucc,
-- * Type-level lists
type (++),
Replicate,
lemReplicateSucc,
MapJust,
lemMapJustEmpty, lemMapJustCons, lemMapJustHead,
Head,
Tail,
Init,
Last,
-- * Unsafe
unsafeCoerceRefl,
) where
import Data.Proxy
import Data.Type.Equality
import GHC.TypeLits
import GHC.TypeNats qualified as TN
import Unsafe.Coerce qualified
-- Reasoning helpers
subst1 :: forall f a b. a :~: b -> f a :~: f b
subst1 Refl = Refl
subst2 :: forall f c a b. a :~: b -> f a c :~: f b c
subst2 Refl = Refl
-- | Evidence for the constraint @c a@.
data Dict c a where
Dict :: c a => Dict c a
{-# INLINE fromSNat' #-}
fromSNat' :: SNat n -> Int
fromSNat' = fromEnum . TN.fromSNat
sameNat' :: SNat n -> SNat m -> Maybe (n :~: m)
sameNat' n@SNat m@SNat = sameNat n m
pattern SZ :: () => (n ~ 0) => SNat n
pattern SZ <- ((\sn -> testEquality sn (SNat @0)) -> Just Refl)
where SZ = SNat
pattern SS :: forall np1. () => forall n. (n + 1 ~ np1) => SNat n -> SNat np1
pattern SS sn <- (snatPred -> Just (SNatPredResult sn Refl))
where SS = snatSucc
{-# COMPLETE SZ, SS #-}
snatSucc :: SNat n -> SNat (n + 1)
snatSucc SNat = SNat
data SNatPredResult np1 = forall n. SNatPredResult (SNat n) (n + 1 :~: np1)
snatPred :: forall np1. SNat np1 -> Maybe (SNatPredResult np1)
snatPred snp1 =
withKnownNat snp1 $
case cmpNat (Proxy @1) (Proxy @np1) of
LTI -> Just (SNatPredResult (SNat @(np1 - 1)) Refl)
EQI -> Just (SNatPredResult (SNat @(np1 - 1)) Refl)
GTI -> Nothing
-- This should be a function in base
snatPlus :: SNat n -> SNat m -> SNat (n + m)
snatPlus n m = TN.withSomeSNat (TN.fromSNat n + TN.fromSNat m) Unsafe.Coerce.unsafeCoerce
-- This should be a function in base
snatMinus :: SNat n -> SNat m -> SNat (n - m)
snatMinus n m = let res = TN.fromSNat n - TN.fromSNat m in res `seq` TN.withSomeSNat res Unsafe.Coerce.unsafeCoerce
-- This should be a function in base
snatMul :: SNat n -> SNat m -> SNat (n * m)
snatMul n m = TN.withSomeSNat (TN.fromSNat n * TN.fromSNat m) Unsafe.Coerce.unsafeCoerce
-- | Type-level list append.
type family l1 ++ l2 where
'[] ++ l2 = l2
(x : xs) ++ l2 = x : xs ++ l2
type family Replicate n a where
Replicate 0 a = '[]
Replicate n a = a : Replicate (n - 1) a
lemReplicateSucc :: forall a n proxy.
proxy n -> a : Replicate n a :~: Replicate (n + 1) a
lemReplicateSucc _ = unsafeCoerceRefl
type family MapJust l = r | r -> l where
MapJust '[] = '[]
MapJust (x : xs) = Just x : MapJust xs
lemMapJustEmpty :: MapJust sh :~: '[] -> sh :~: '[]
lemMapJustEmpty Refl = unsafeCoerceRefl
lemMapJustCons :: MapJust sh :~: Just n : sh' -> sh :~: n : Tail sh
lemMapJustCons Refl = unsafeCoerceRefl
lemMapJustHead :: proxy sh1 -> Head (MapJust sh1) :~: Just (Head sh1)
lemMapJustHead _ = unsafeCoerceRefl
type family Head l where
Head (x : _) = x
type family Tail l where
Tail (_ : xs) = xs
type family Init l where
Init (x : y : xs) = x : Init (y : xs)
Init '[x] = '[]
type family Last l where
Last (x : y : xs) = Last (y : xs)
Last '[x] = x
-- | This is just @'Unsafe.Coerce.unsafeCoerce' 'Refl'@, but specialised to
-- only typecheck for actual type equalities. One cannot, e.g. accidentally
-- write this:
--
-- @
-- foo :: Proxy a -> Proxy b -> a :~: b
-- foo = unsafeCoerceRefl
-- @
--
-- which would have been permitted with normal 'Unsafe.Coerce.unsafeCoerce',
-- but would have resulted in interesting memory errors at runtime.
unsafeCoerceRefl :: a :~: b
unsafeCoerceRefl = Unsafe.Coerce.unsafeCoerce Refl