2015-10-31 75 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