Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何确定嵌套通用量词的范围(更高级别的类型)?_Haskell_Functional Programming_Quantifiers_Unification_Higher Rank Types - Fatal编程技术网

Haskell 如何确定嵌套通用量词的范围(更高级别的类型)?

Haskell 如何确定嵌套通用量词的范围(更高级别的类型)?,haskell,functional-programming,quantifiers,unification,higher-rank-types,Haskell,Functional Programming,Quantifiers,Unification,Higher Rank Types,最初,我假设函数类型LHS上嵌套的通用量词的范围可以纯语法确定,即(对于所有a.a->b)->Bool的括号内的所有内容都在同一范围内。然而,这一假设是错误的: {-# LANGUAGE RankNTypes #-} fun :: (forall a. [a] -> b) -> Bool fun _ = undefined arg :: c -> c arg _ = undefined r = fun arg -- type variable a would escape

最初,我假设函数类型LHS上嵌套的通用量词的范围可以纯语法确定,即
(对于所有a.a->b)->Bool
的括号内的所有内容都在同一范围内。然而,这一假设是错误的:

{-# LANGUAGE RankNTypes #-}

fun :: (forall a. [a] -> b) -> Bool
fun _ = undefined

arg :: c -> c
arg _ = undefined

r = fun arg -- type variable a would escape its scope
这是有意义的,因为在
fun
b
中必须在
a
之前选择,因此必须固定或独立于
a
。在统一过程中,参数类型
c->c
将强制
b
使用
[a0]
进行实例化

因此,类型级别的作用域可能非常类似于术语级别的函数,其中结果值显然不属于函数的作用域。换句话说,如果
b
不是函数类型的密码域,则类型检查器将通过。不幸的是,我无法找到支持我推理的注释


一种限制性更强的方法是,在统一过程中,不允许使用同一注释的任何灵活类型实例化刚性类型变量。这两种方法对我来说似乎都是合理的,但这在Haskell中究竟是如何工作的呢?

非量化类型变量在顶层被隐式量化。你的类型相当于

fun :: forall b . (forall a. [a] -> b) -> Bool
arg :: forall c . c -> c
因此,
b
的范围是整个类型

您可以将所有'ed变量的每个看作函数接收的一种隐式附加类型参数。我想你明白,在一个签名中

foo :: Int -> (String -> Bool) -> Char
Int
值由
foo
的调用者选择,而
String
值由
foo
在调用作为第二个参数传递的函数时(和如果)选择

本着同样的精神,

fun :: forall b. (forall a. [a] -> b) -> Bool
表示
b
fun
的调用者选择,而
a
fun
本身选择

调用方确实可以使用
TypeAnnotations
显式地传递
b
类型并写入

fun @Int :: (forall a. [a] -> Int) -> Bool
之后,将为所有a生成一个
类型的参数。[a] ->Int
必须是apssed,并且
length
适合这种多态类型

fun @Int length :: Bool
因为这是
fun
的调用站点,所以我们看不到“type参数”
a
在哪里传递。这确实只能在
fun
的定义中找到

事实证明,实际上不可能定义一个
fun
,该类型对其参数进行有意义的调用(
length
,如上)。如果我们有这样一个稍微不同的签名:

fun :: forall b. Eq b => (forall a. [a] -> b) -> Bool
fun f = f @Int [1,2,3] /= f @Bool [True, False]

这里我们可以看到,
f
(通过调用绑定到
length
)在两种不同的类型上被调用了两次。这将生成两个类型为
b
的值,然后可以对其进行比较,以生成最终的
Bool

非量化类型变量在顶级隐式量化。你的类型相当于

fun :: forall b . (forall a. [a] -> b) -> Bool
arg :: forall c . c -> c
因此,
b
的范围是整个类型

您可以将所有'ed变量的每个看作函数接收的一种隐式附加类型参数。我想你明白,在一个签名中

foo :: Int -> (String -> Bool) -> Char
Int
值由
foo
的调用者选择,而
String
值由
foo
在调用作为第二个参数传递的函数时(和如果)选择

本着同样的精神,

fun :: forall b. (forall a. [a] -> b) -> Bool
表示
b
fun
的调用者选择,而
a
fun
本身选择

调用方确实可以使用
TypeAnnotations
显式地传递
b
类型并写入

fun @Int :: (forall a. [a] -> Int) -> Bool
之后,将为所有a生成一个
类型的参数。[a] ->Int
必须是apssed,并且
length
适合这种多态类型

fun @Int length :: Bool
因为这是
fun
的调用站点,所以我们看不到“type参数”
a
在哪里传递。这确实只能在
fun
的定义中找到

事实证明,实际上不可能定义一个
fun
,该类型对其参数进行有意义的调用(
length
,如上)。如果我们有这样一个稍微不同的签名:

fun :: forall b. Eq b => (forall a. [a] -> b) -> Bool
fun f = f @Int [1,2,3] /= f @Bool [True, False]

这里我们可以看到,
f
(通过调用绑定到
length
)在两种不同的类型上被调用了两次。这将生成两个类型为
b
的值,然后可以对其进行比较,以生成最终的
Bool

对于没有显式
forall
的任何变量,隐式的值将插入最近的
,因此您的示例相当于
fun::forall b。(forall a.[a]->b)->Bool
我发现将
forall
视为lambda的类型级别等价物非常有用。与您的示例类似的术语级示例看起来像
fun=\b->(\a->[a]`foo`b)`bar`True
@FyodorSoikin,这听起来有点不对劲。类型lambda是支持它们的语言中的术语级别的东西。Haskell的
forall
只是一种在类型签名中显式显示类型参数的方法<代码>全部a。[a] ->b是一个术语的类型,其第一个参数是类型,
a
,第二个参数是类型
a
@DFEU的值,因为它们不仅仅是“明确的方式”,它们对于指定范围很重要。在rank-N类型之前,只有一个可能的作用域,因此Haskell对所有的都没有,但现在作用域可以不同了,这就突然需要了。看看我前段时间写的,它有一点关于这个主题。@FyodorSoikin,对,他们指定了范围。它们绑定名称,就像lambdas一样,但在其他方面却完全不同。对于没有显式
forall
的任何变量,隐式变量正好插入最近的
,因此您的示例相当于
fun::forall b。(全部a)