我有一个简单的Nat定义和Nat?索引的类型定义。
data Nat :: * where
Zero :: Nat
Suc :: Nat -> Nat deriving(Show, Typeable)
data Natty :: Nat -> * where
Zy :: Natty Zero
Sy :: Natty n -> Natty (Suc n) deriving Typeable
我希望使用Type.Reflection模块以通用方式存储和操作这些Natty。
作为Nat存储作为类型代表工作正常。
foo :: Nat -> SomeTypeRep
foo x = SomeTypeRep (typeOf x)
但是,除非添加额外的约束,否则将Natty存储为类型代表并不起作用。
boo :: Natty n -> SomeTypeRep
boo x = SomeTypeRep (typeOf x)
boo会产生以下错误:
No instance for (Typeable n) arising from the use of 'typeOf'
我的问题是为什么Haskell不能识别n是nat,因此应该是Typeable?
就像我说的,我可以通过将类型n的约束添加到boo的开头来解决这个问题,但是当我使用在另一个函数的中间返回natty的函数时就不那么简单了。
已使用以下扩展和导入。
{-# LANGUAGE DataKinds, KindSignatures, GADTs #-}
import Type.Reflection
答案 0 :(得分:1)
添加Typeable n
反映了GHC需要将Typeable
字典传入boo
的情况,如果调用n
实例化不同的话。
围绕Typeable
和DataKinds
的相互作用有一些聪明之处。 GHC派生的实例大致相当于
instance Typeable Nat where ...
instance Typeable 'Zero where ...
instance Typeable n => Typeable ('Suc n) where ...
Typeable n
实例不会填写提示您添加的Typeable Nat
约束(请记住n
有Nat
种,而不是*
}!),但是受后两种约束。
但是,我可以听到你说,为什么GHC可以通过对这两个实例的简单归纳来确定所有n :: Nat
都是Typeable
?因为'Zero
和'Suc
不是制作某种类型的唯一方式Nat
...
ghci> type family Stuck :: k
ghci> :kind Natty Stuck -- a valid type!
Natty Stuck :: *
换句话说,GHC在编译时不能知道n :: Nat
是Typeable
,你需要将它传递给这个事实的运行时见证。
答案 1 :(得分:1)
您可以实现所需的功能,但不是免费的。
boof :: Natty n -> TypeRep n
boof Zy = typeRep
boof (Sy n) = withTypeable (boof n) typeRep
更明确地说明(这基本上是boof
内部发生的事情):
goo :: Natty n -> TypeRep n
goo Zy = typeRep @'Zero
goo (Sy n) = App (typeRep @'Suc) (goo n)
如goo
所示,TypeRep
的结构实际上与Natty
的结构非常相似。实际上,你也可以采取其他方式,尽管你无法说服模式检查者总是:
hum :: TypeRep n -> Natty n
hum (App s n)
| Just HRefl <- eqTypeRep s (typeRep @'S) = Sy (hum n)
| otherwise = error "imp possible"
hum z
| Just HRefl <- eqTypeRep z (typeRep @'Z) = Zy
| otherwise = error "impposs ible"
您可以按照自己的意愿结束结果:
boo :: Natty n -> SomeTypeRep
boo n = SomeTypeRep (boof n)
但似乎你应该使用比SomeTypeRep
更具体的东西。 Typeable
内部实际上使用了这个:
data SomeKindedTypeRep k where
SomeKindedTypeRep :: forall (x :: k). Typeable x => SomeKindedTypeRep k
您可以定义并使用SomeKindedTypeRep Nat
,或仅为Nat
定义专用版本。这样你就不会因为你故意忘记这种类型而忘记那种(在编译时就知道)。