2011-10-03 36 views
14

在閱讀QuickCheck Manual,我碰到下面的例子:在'哪裏'的類型聲明 - 發生了什麼?

prop_RevRev xs = reverse (reverse xs) == xs 
    where types = xs::[Int] 

該手冊接着說:

屬性必須有單態類型。 「多態」屬性(例如上面的屬性)必須限制爲用於測試的特定類型。是很方便的,說明該類型中的一個或多個參數的

這樣做,其中類型=(X1 :: T1,X2 :: T2,...)

條款。請注意,類型不是關鍵字;這只是一個本地聲明,它提供了一個方便的地方來限制x1,x2等類型。

我以前從未在Haskell中見過這樣的伎倆。這是我真正遇到的問題:

  1. 爲什麼類型聲明的語法甚至存在?它可以爲我做什麼,以下不能?

    prop_RevRev :: [Int] -> Bool 
    prop_RevRev xs = reverse (reverse xs) == xs 
    
  2. 這是否使用where構成類型聲明「特殊」的語法?或者它是一致的和合乎邏輯的(如果是這樣,如何?)?

  3. 這是用法標準還是傳統的Haskell?

回答

14

where對於類型聲明不是特殊的語法。例如,這個工程:

prop_RevRev :: [Int] -> Bool 
prop_RevRev xs = ys == xs 
    where ys = reverse (reverse xs) 

等做到這一點:

prop_RevRev xs = ys == xs 
    where ys = reverse (reverse xs) 
     ys :: [Int] 

where type = (xs :: [Int])超過prop_RevRev :: [Int] -> Bool的優點是,在後一種情況下,你必須指定返回類型,而在前者的情況下編譯器可以爲你推斷它。如果你有一個非Boolean特性,例如這無關緊要:

prop_positiveSum xs = 0 < length xs && all (0 <) xs ==> 0 < sum xs 
    where types = (xs :: [Int]) 
+0

我一直在想這件事很久。謝謝。 – sykora

+1

@MattFenwick:您可以在任何級別的任何子表達式中添加一個類型註釋,所以當您只想填寫編譯器無法推斷的細節時,此技巧非常有用,無需指定完整類型簽名。但是,它們仍然必須是一致的,例如, '(x :: Float)+(x :: Int)'會導致類型錯誤。 – hammar

+1

所以基本上'type'或'types'是一個不使用的虛擬變量;只是爲了方便在其他表達式上的類型警衛 – newacct

4

它沒有特殊的語法,有時候你只需要它,就像在下面的情況:

foo :: String -> String 
foo s = show (read s) 

因爲它站,這是不能鍵入的,因爲值read s的類型不能被識別。所有已知的是它必須是Show和Read的一個實例。但是這種類型根本不會出現在類型簽名中,所以也不可能將其留在那個類型並推斷出受限類型。 (沒有可能受到限制的類型變量。)

有趣的是,要注意的是什麼呢read s完全取決於類型簽名人給read s,例如:

read "Just True" :: (Maybe Bool) 

會成功,而

read "Just True" :: (Maybe Int) 

不會。