如何编写通用量化函数的存在版本?
How can I write an Existential version of a Universally quantified function?
我有一个依赖类型问题,我正在尝试解决,我已将其缩小为以下漫画,即从大小向量中删除索引:
TL;DR 给定rmIx
,我怎么写someRmIx
?
rmIx :: forall ix n a. Vector (n+1) a -> Vector n a
someRmIx :: forall ix a. SomeVector a -> SomeVector a
在 someRmIx
版本中,我需要在 rmIx
函数中获得约束的见证,并且,如果我不能满足这些约束(例如,你不能从Vector 0 a
), 然后 return SomeVector
不变.
module SomeVector where
import qualified Data.Vector.Sized as V
import Data.Vector.Sized
import GHC.TypeNats
import Data.Proxy
import Type.Reflection
import Data.Type.Equality
import Unsafe.Coerce (unsafeCoerce)
import Data.Data (eqT)
data SomeVector a = forall n. KnownNat n => SomeVector (Vector n a)
-- | Remove an index from an existentially sized 'Vector'.
someRmIx :: forall (ix :: Nat) a m. KnownNat ix => SomeVector a -> SomeVector a
someRmIx (SomeVector (v :: Vector n a)) =
--------------------------------------------------
--------------------------------------------------
--------------------------------------------------
-- WHAT DO I DO HERE???
--------------------------------------------------
--------------------------------------------------
--------------------------------------------------
case ??????? of
Nothing -> SomeVector v
Just Refl -> SomeVector $ rmIx @ix v
-- | Remove an index of a 'Vector'.
rmIx :: forall (ix :: Nat) n a (m :: Nat).
(ix <= n, -- in my actual code I clean this up with GHC.TypeLits.Normalise
KnownNat ix,
(ix + m) ~ n,
((n - ix) + 1) ~ (1 + m),
(n + 1) ~ (ix + (1 + m))
)
=> Vector (n+1) a -> Vector n a
rmIx v = l V.++ r
where (l :: Vector ix a, r' :: Vector (n-ix+1) a) = V.splitAt' (Proxy @ix) v
(r :: Vector m a) = V.drop' (Proxy @1) r'
----------
-- * Tests
myV :: Vector 5 Int
myV = let Just v = V.fromList [1,2,3,4,5]
in v
test1 :: Vector 4 Int
test1 = rmIx @2 myV
test2 :: SomeVector Int
test2 = someRmIx @2 $ SomeVector myV
编译以上内容的必要大张旗鼓:
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
我有一个依赖类型问题,我正在尝试解决,我已将其缩小为以下漫画,即从大小向量中删除索引:
TL;DR 给定rmIx
,我怎么写someRmIx
?
rmIx :: forall ix n a. Vector (n+1) a -> Vector n a
someRmIx :: forall ix a. SomeVector a -> SomeVector a
在 someRmIx
版本中,我需要在 rmIx
函数中获得约束的见证,并且,如果我不能满足这些约束(例如,你不能从Vector 0 a
), 然后 return SomeVector
不变.
module SomeVector where
import qualified Data.Vector.Sized as V
import Data.Vector.Sized
import GHC.TypeNats
import Data.Proxy
import Type.Reflection
import Data.Type.Equality
import Unsafe.Coerce (unsafeCoerce)
import Data.Data (eqT)
data SomeVector a = forall n. KnownNat n => SomeVector (Vector n a)
-- | Remove an index from an existentially sized 'Vector'.
someRmIx :: forall (ix :: Nat) a m. KnownNat ix => SomeVector a -> SomeVector a
someRmIx (SomeVector (v :: Vector n a)) =
--------------------------------------------------
--------------------------------------------------
--------------------------------------------------
-- WHAT DO I DO HERE???
--------------------------------------------------
--------------------------------------------------
--------------------------------------------------
case ??????? of
Nothing -> SomeVector v
Just Refl -> SomeVector $ rmIx @ix v
-- | Remove an index of a 'Vector'.
rmIx :: forall (ix :: Nat) n a (m :: Nat).
(ix <= n, -- in my actual code I clean this up with GHC.TypeLits.Normalise
KnownNat ix,
(ix + m) ~ n,
((n - ix) + 1) ~ (1 + m),
(n + 1) ~ (ix + (1 + m))
)
=> Vector (n+1) a -> Vector n a
rmIx v = l V.++ r
where (l :: Vector ix a, r' :: Vector (n-ix+1) a) = V.splitAt' (Proxy @ix) v
(r :: Vector m a) = V.drop' (Proxy @1) r'
----------
-- * Tests
myV :: Vector 5 Int
myV = let Just v = V.fromList [1,2,3,4,5]
in v
test1 :: Vector 4 Int
test1 = rmIx @2 myV
test2 :: SomeVector Int
test2 = someRmIx @2 $ SomeVector myV
编译以上内容的必要大张旗鼓:
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}