2015-10-31 30 views
5

,同时通过GHC扩展工作我的方式,我遇到RankNTypes at the School of Haskell,其中有下面的例子来不同之处在于“后一个签名需要从n到n的某个Num n的函数;前一个签名对于每个Num n需要一个从n到n的函数。”理解Haskell的RankNTypes

我可以理解,前一种类型需要签名是括号内或更一般的。我不理解后面的签名只需要“某些Num n”的功能n -> n的解释。有人可以详细说明吗?你如何“读”这个前签名,使其听起来像是什么意思?后者的签名是否与Num n => (n -> n) -> (Int, Double)相同,而不需要forall

+0

将函数的主体想象为:'(f(1 :: Int),f(1.0 :: Double))''。你不能使用后者的类型签名。在'Num n => n - > n - >(Int,Double)''中,'n'必须同时是'Int'和'Double' * *。使用'(forall n。num n => n - > n) - >(Int,Double)'你可以将函数'f'应用于不同的类型,因此它的输入很好。 – Bakuriu

回答

6

在正常情况下(forall n. Num n => (n -> n) -> (Int, Double)),我们选择一个n第一然后提供一个功能。所以我们可以通过Int -> IntDouble -> DoubleRational -> Rational等类型的函数。

在等级2的情况下((forall n. Num n => n -> n) -> (Int, Double))我们必须提供功能才知道n。这意味着该功能必须适用于任何n;我没有列出前例的例子。

我们需要这样的代码给出,因为传入的函数f应用于两种不同类型:IntDouble。所以它必须为他们两个工作。

第一种情况是正常的,因为这是默认情况下类型变量的工作原理。如果您根本没有forall,那么您的类型签名就相当于在一开始就拥有它。 (这被称为prenex表格)。因此Num n => (n -> n) -> (Int, Double)隐含地与forall n. Num n => (n -> n) -> (Int, Double)相同。

这是什么类型的功能,适用于任何n?这正是forall n. Num n => n -> n

+0

谢谢。在“排名N”中,排名意味着什么,N是指什么? – Ana

+1

'N'表示你可以在函数内嵌入'forall'的深度(' - >')。在这种情况下,它嵌套在单个函数中,因此它是等级2. Haskell过去*只支持Rank2多态,但由于它现在支持任意等级,这更多的是历史记录。 –

2

你如何“读”这个前签名,使它听起来像是什么意思?

您可以阅读

rankN :: (forall n. Num n => n -> n) -> (Int, Double) 

为“rankN需要一个参数f :: Num n => n -> n”,并返回(Int, Double),其中f :: Num n => n -> n可以被解读为“对任何数值类型nf可以采取n并返回n ”。

秩一个定义

rank1 :: forall n. Num n => (n -> n) -> (Int, Double) 

然后将被读为“对于任何数值类型nrank1接受一个参数f :: n -> n并返回(Int, Double)”。

后者的签名是否与Num n => (n -> n) -> (Int, Double)相同,而不需要forall

是的,默认情况下,所有的forall都被隐含地放置在最外面的位置(导致秩-1类型)。

2

rankN的情况下,f必须是一个多态函数,它对所有数字类型n有效。

rank1的情况下f只需定义为单个数字类型。

下面是一些代码,说明了这一点:

{-# LANGUAGE RankNTypes #-} 

rankN :: (forall n. Num n => n -> n) -> (Int, Double) 
rankN = undefined 

rank1 :: forall n. Num n => (n -> n) -> (Int, Double) 
rank1 = undefined 

foo :: Int -> Int -- monomorphic 
foo n = n + 1 

test1 = rank1 foo -- OK 

test2 = rankN foo -- does not type check 

test3 = rankN (+1) -- OK since (+1) is polymorphic 

更新

在回应@ helpwithhaskell在评论问题...

考虑一下这个功能:

bar :: (forall n. Num n => n -> n) -> (Int, Double) -> (Int, Double) 
bar f (i,d) = (f i, f d) 

也就是说,我们应用f双方一个Int和双。如果不使用RankNTypes它不会键入检查:

-- doesn't work 
bar' :: ??? -> (Int, Double) -> (Int, Double) 
bar' f (i,d) = (f i, f d) 

无下列签名工作,为???:

Num n => (n -> n) 
Int -> Int 
Double -> Double 
+0

为什么要求rankN情况?要求多态参数提供什么优势? – helpwithhaskell

+0

@helpwithhaskell - 答案更新 – ErikR