理解 Haskell 的 RankNTypes [英] Understanding Haskell's RankNTypes
问题描述
在使用 GHC 扩展的过程中,我遇到了 RankNTypes
在 Haskell 学院,其中有以下示例:
While working my way through GHC extensions, I came across RankNTypes
at the School of Haskell, which had the following example:
main = print $ rankN (+1)
rankN :: (forall n. Num n => n -> n) -> (Int, Double)
rankN f = (f 1, f 1.0)
这篇文章为 rankN
提供了另一种类型:
The article offered an alternative type for rankN
:
rankN :: forall n. Num n => (n -> n) -> (Int, Double)
区别的解释是
后一个签名需要一个从 n 到 n 的函数,用于某些 Num n;前一个签名要求每个 Num n 都有一个从 n 到 n 的函数.
The latter signature requires a function from n to n for some Num n; the former signature requires a function from n to n for every Num n.
我可以理解,前一种类型需要签名才能在括号中或更一般的内容.我不明白后一个签名只需要一个函数 n -> 的解释.n
表示某些 Num n
".有人可以详细说明和澄清吗?你如何阅读"?这个以前的签名让这听起来像什么意思?后一个签名是否与简单的 Num n => 相同?(n -> n) ->(Int, Double)
不需要forall
?
I can understand that the former type requires a signature to be what's in the parentheses or more general. I do not understand the explanation that the latter signature simply requires a function n -> n
for "some Num n
". Can someone elaborate and clarify? How do you "read" this former signature so that it sounds like what it means? Is the latter signature the same as simply Num n => (n -> n) -> (Int, Double)
without the need for forall
?
推荐答案
在正常情况下 (forall n.Num n => (n -> n) -> (Int, Double)
),我们选择一个 n
first 然后提供一个函数.所以我们可以传入一个 Int -> 类型的函数.Int
, 双 ->Double
, Rational ->理性
等.
In the normal case (forall n. Num n => (n -> n) -> (Int, Double)
), we choose an n
first and then provide a function. So we could pass in a function of type Int -> Int
, Double -> Double
, Rational -> Rational
and so on.
在 Rank 2 的情况下 ((forall n. Num n => n -> n) -> (Int, Double)
) 我们必须提供函数 before 我们知道 n
.这意味着该函数必须适用于any n
;我为上一个示例列出的所有示例都不起作用.
In the Rank 2 case ((forall n. Num n => n -> n) -> (Int, Double)
) we have to provide the function before we know n
. This means that the function has to work for any n
; none of the examples I listed for the previous example would work.
我们在给出的示例代码中需要这个,因为传入的函数 f
应用于两种不同的类型:Int
和 Double
>.所以它必须对他们两个都有效.
We need this for the example code given because the function f
that's passed in is applied to two different types: an Int
and a Double
. So it has to work for both of them.
第一种情况是正常的,因为默认情况下类型变量就是这样工作的.如果您根本没有 forall
,那么您的类型签名就相当于在一开始就拥有它.(这称为前缀形式.)所以 Num n =>(n -> n) ->(Int, Double)
与 forall n 隐含相同.数 n =>(n -> n) ->(Int, Double)
.
The first case is normal because that's how type variables work by default. If you don't have a forall
at all, your type signature is equivalent to having it at the very beginning. (This is called prenex form.) So Num n => (n -> n) -> (Int, Double)
is implicitly the same as forall n. Num n => (n -> n) -> (Int, Double)
.
适用于any n
的函数类型是什么?这正是 forall n.数 n =>n ->n
.
What's the type of a function that works for any n
? It's exactly forall n. Num n => n -> n
.
这篇关于理解 Haskell 的 RankNTypes的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!