繁体   English   中英

为什么 `fx = xx` 和 `gx = xxxxx` 具有相同的类型

[英]Why `f x = x x` and `g x = x x x x x` have the same type

我正在玩 Rank-N-type 并尝试输入xx 但是我发现这两个函数可以以相同的方式输入是违反直觉的。

f :: (forall a b. a -> b) -> c
f x = x x

g :: (forall a b. a -> b) -> c
g x = x x x x x

我还注意到fx = xx ... xx (many x s) 之类的东西仍然具有相同的类型。 谁能解释为什么会这样?

关键是x :: a -> b是一个可以提供任何类型值的函数,无论给出什么参数。 这意味着x可以应用于自身,结果可以再次应用于x ,依此类推。

至少,这就是它承诺的类型检查器可以做的事情。 类型检查器不关心是否存在任何这样的值,只关心类型是否对齐。 fg实际上都不能被调用,因为不存在a -> b类型a -> b值(忽略 bottom 和unsafeCoerce )。

这不应该比以下事实更令人惊讶

m :: (∀ a . a) -> (∀ a . a) -> (Int, Bool)
m p q = (p, q)

具有相同的类型

n :: (∀ a . a) -> (∀ a . a) -> (Int, Bool)
n p q = (q, p)

就像在您的示例中一样,这是有效的,因为通用量化参数可以以多种不同的方式使用,编译器在每种情况下都会选择适当的类型并强制x充当具有该类型的角色。

这实际上是一个相当人为的情况,因为像∀ a . a这样的类型∀ a . a ∀ a . a∀ ab . a->b ∀ ab . a->b是无人居住的(模⊥),因此您实际上永远无法使用带有此类参数的 RankN 函数; 实际上,那时你甚至不会它!

实用的 RankN 函数通常会在其参数中强加一些额外的结构或类型类约束,例如

foo :: (∀ a . [a] -> [a]) -> ...

或者

qua :: (∀ n . Num n -> Int -> n -> n) -> ...

一个更简单的例子

每当我们使用具有多态类型的变量(例如您的x )时,都可以观察到这种现象。 身份函数id可能是最著名的例子。

id :: forall a . a -> a

在这里,所有这些表达式都进行类型检查,并且类型为Int -> Int

id :: Int -> Int
id id :: Int -> Int
id id id :: Int -> Int
id id id id :: Int -> Int
...

这怎么可能? 好吧,关键是每次我们写id我们实际上是指“应该从上下文中推断出的某个未知类型a上的身份函数”。 至关重要的是,每次使用id都有自己的a

让我们写id @T来表示类型T上的特定标识函数。

写作

id :: Int -> Int

实际上是指

id @Int :: Int -> Int

这很简单。 相反,写

id id :: Int -> Int

实际上是指

id @(Int -> Int) (id @Int) :: Int -> Int

其中第一个id现在指的是函数空间Int -> Int 而且当然,

id id id :: Int -> Int

方法

(id @((Int -> Int) -> (Int -> Int))) (id @(Int -> Int)) (id @Int) :: Int -> Int

等等。 我们没有意识到类型会变得如此混乱,因为 Haskell 会为我们推断这些类型。

具体案例

在您的具体情况下,

g :: (forall a b. a -> b) -> c
g x = x x x x x

我们可以通过多种方式进行类型检查。 一种可能的方法是定义A ~ Int , B ~ Bool , T ~ (A -> B)然后推断:

g x = x @T @(T -> T -> T -> c) (x @A @B) (x @A @B) (x @A @B) (x @A @B)

我建议花一些时间来了解所有类型的检查。 (此外,我们对AB选择是完全任意的,我们可以在那里使用任何其他类型。我们甚至可以为每个x使用不同的A s 和B s,只要第一个x被适当地实例化!)

很明显,即使当xxx ...是一个更长的序列时,这种推断也是可能的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM