Haskell “forall'”的等级和范围;

Haskell “forall'”的等级和范围;,haskell,higher-rank-types,Haskell,Higher Rank Types,这两者有什么区别 {-# LANGUAGE RankNTypes #-} f :: forall a. a -> Int f _ = 1 g :: (forall a. a) -> Int g _ = 1 特别是,为什么我会在g()中遇到错误 ghci>f() 1. ghci>g() :133:3: 无法将预期类型“a”与实际类型“()”匹配 `a'是一个刚性类型变量,由 上下文所需的类型:a at:133:1 在“g”的第一个参数中,即“()” 在表达式中:g() 在‘it’

这两者有什么区别

{-# LANGUAGE RankNTypes #-}

f :: forall a. a -> Int
f _ = 1

g :: (forall a. a) -> Int
g _ = 1
特别是,为什么我会在
g()
中遇到错误

ghci>f()
1.
ghci>g()
:133:3:
无法将预期类型“a”与实际类型“()”匹配
`a'是一个刚性类型变量,由
上下文所需的类型:a at:133:1
在“g”的第一个参数中,即“()”
在表达式中:g()
在‘it’的方程式中:it=g()
ghci>f未定义
1.
ghci>g未定义
1.

f
只是一个普通的多态Haskell98函数,除了所有的
都是显式写出的。因此,签名中的所有类型变量都是调用者可以选择的参数(没有任何约束);在您的情况下,它被解析为
a~()

g
OTOH有一个等级为2的类型。它要求它的参数对于所有a都具有多态类型
。a
()
没有这样的类型,它是单态的。但是
undefined
有这种类型(实际上,只有undefined和error等),如果我们再次为all
添加显式

也许通过一个不那么琐碎的Rank2函数会变得更清晰:

h :: (forall a . (Show a, Num a) => a) -> String
h a = show a1 ++ " :: Double\n"
     ++ show a2 ++ " :: Int"
 where a1 :: Double; a2 :: Int
       a1 = a; a2 = a
GHCi>putStrLn$h4
4.0::双倍
4::Int

但我做不到

GHCi>putStrLn$h(4::整数)

:4:15:
无法推断(a~整数)
从上下文(显示a,数字a)
由上下文预期的类型绑定:(Show a,Num a)=>a
时间:4:12-27
'a'是由
上下文所需的类型:(Show a,Num a)=>a
时间:4:12
在“h”的第一个参数中,即“(4::Integer)”
在“($)”的第二个参数中,即“h(4::Integer)”
表达式中:putStrLn$h(4::Integer)


forall
视为一个匿名类型函数。Haskell中所有在其类型签名中包含类型变量的数据类型都隐式地具有一个
forall
。例如,考虑:

f :: a -> Int
f _ = 1
上述函数
f
接受任何类型的参数并返回
Int
a
来自哪里?它来自所有
量词的
。因此,它相当于:

f :: (forall a . a -> Int)
f _ = 1
forall
quatifier可用于任何数据类型,而不仅仅是函数。例如,考虑以下值的类型:

() :: ()
10 :: Int
pi :: Floating a => a
这里的
()
10
是单态的(即它们只能是一种混凝土类型)。另一方面,
pi
具有类型类约束的多态性(即,它可以是任何类型,只要该类型是
浮动
的实例)。明确写出的
pi
类型为:

pi :: (forall a . Floating a => a)
同样地,
forall
量词的作用类似于类型函数。它为您提供类型变量
a
。现在考虑函数的类型<代码> g < /代码>:

g :: (forall a . a) -> Int
g _ = 1
这里,
g
要求所有a都使用类型为
的参数。a
并返回一个
Int
。这就是
g()
不起作用的原因:
()
属于
()
类型,而不是所有类型的
。a
。实际上,类型
对于所有a的唯一值。a
未定义的

undefined :: a
forall
明确写出:

undefined :: (forall a . a)
如果您注意到,我总是在所有
量化的
后面加括号。我这样做的原因是向您展示,当您对函数使用
进行所有
量化时,量化会一直向右扩展。这就像lambda:如果不在lambda周围加上括号,Haskell将把lambda函数一直扩展到右边。因此,
f
的类型是
(对于所有a.a->Int)
,而不是
(对于所有a.a)->Int


请记住,在第一种情况下,Haskell希望参数的类型为
a
(即任何类型)。但是,在第二种情况下,Haskell希望参数的类型为
(对于所有a.a)
(即
未定义
)。当然,如果您试图计算
未定义的
,那么您的程序将立即因错误而停止。幸运的是,您没有尝试对它进行评估。

您是说
()
是单态的(在哪一类?),还是说
()
对其他(未指定)对象是单态的?或者你是在以其他方式使用“单态”这个词吗?@Snowball:我是在Haskell的上下文中使用这个词的:不是多态的东西。事实上,我从来没有想过这与单态有什么关系……我不认为这与单态的范畴论概念有任何联系。TLDR
forall的
可以在类型级别上被视为lambdas,
\a->M~>N
(\a->M)~>N
调用forall不同“类型级别的lambda”不准确,请参阅:。
undefined :: (forall a . a)