Haskell 理解“GHC.TypeLits”`
我正试图对GHC扩展Haskell 理解“GHC.TypeLits”`,haskell,ghc,Haskell,Ghc,我正试图对GHC扩展KindSignatures和datatypes了如指掌。从包装上看,我大致明白这一点 newtype i `Mod` (n :: Nat) = Mod i deriving (Eq, Ord) 类似于声明C++模板 (构造函数只使用一个类型的代码 t>代码>。然而,看着这个包裹,我不明白发生了什么。任何关于此包的一般性解释都会有所帮助。在这个问题被标记为离题之前,这里有一些具体的子问题: KnownNat类是有意义的,所需的函数允许您从类型中提取类型变量,但是natVa
KindSignatures
和datatypes
了如指掌。从包装上看,我大致明白这一点
newtype i `Mod` (n :: Nat) = Mod i deriving (Eq, Ord)
类似于声明C++模板<代码> <代码>(构造函数只使用一个类型的代码<代码> t>代码>。然而,看着这个包裹,我不明白发生了什么。任何关于此包的一般性解释都会有所帮助。在这个问题被标记为离题之前,这里有一些具体的子问题:
类是有意义的,所需的函数允许您从类型中提取类型变量,但是KnownNat
做什么,以及natVal
类型变量是什么proxy
- 您将在哪里使用
someNatVal
- 最后,什么是
——类型级别号怎么可能是未知的?在编译时,类型级别编号的整个点不就是已知的吗SomeNat
- 这个问题相当广泛——我只讲几点
代理
类型变量只是*->*
类型的类型变量,即类型构造函数的类型。实际上,如果你有一个功能
foo :: proxy a -> ...
bar :: N -> ...
您可以将类型为的值传递给它,例如Maybe Int
,选择proxy=Maybe
和a=Int
。您还可以传递类型为[]Char
(也称为[Char]
)的值。或者,更常见的是,类型为Proxy Int
的值,其中Proxy
是定义为
data Proxy a = Proxy
i、 e.一种数据类型,它不携带任何运行时信息(只有一个值!),但携带编译时信息(幻象类型变量a
)
假设N
是一种Nat
——编译时自然语言。我们可以写一个函数
foo :: proxy a -> ...
bar :: N -> ...
但是调用它需要我们构建一个N
类型的值——这是无关紧要的。类型N
的目的只是携带编译时信息,它的运行时值不是我们真正想要使用的东西。事实上,N
可能根本没有值,除了底部。我们可以打电话
但这看起来很奇怪。阅读本文,我们必须意识到,bar
在其第一个参数中是懒惰的,并且在尝试使用它时不会引起分歧。问题在于,bar::N->…
类型签名具有误导性:它声称结果可能取决于N
类型的参数值,而实际情况并非如此。相反,如果我们使用
baz :: Proxy N -> ...
意图很清楚——只有一个运行时值:Proxy::Proxy N
。同样清楚的是,N
值只在编译时出现
有时,代码不是使用特定的代理N
,而是稍微泛化为
foo :: proxy N -> ...
它实现了相同的目标,但也允许不同的代理
类型。(就我个人而言,我对这一概括并不感到非常激动。)
回到问题:natVal
是一个函数,它将编译时纯自然值转换为运行时值。也就是说,它将Proxy N
转换为Int
,只返回常量
<>你如果使用类型模板参数来编译编译时间自然,你可以更接近C++模板。例如
模板结构{使用pred=N;};
结构Z{};
模板int natVal();
模板int natVal(){return 1+natVal();}
template int natVal(){return 0;}
int main(){
使用代理的一个重要原因可能是,您试图传递的类型级别a
可能没有种类*
。例如,proxy 3->b
很相似,但是3->b
不相似;proxy Maybe->b
很相似,但是Maybe->b
不相似。此外,未定义::N
只有在N有kind*时才是好的kind。不,类型不必在编译时都知道。例如,在编译id
时,不知道所有可能的参数都是什么。@奥古斯特的观点很好,但是SomeNat
的目的是什么?它是一个存在量化类型的类型。你知道它是一种Nat,但不确切是哪种类型。