[英]When are type signatures necessary in Haskell?
許多介紹性文本將告訴您,在Haskell類型簽名中,“幾乎總是”是可選的。 有人可以量化“幾乎”部分嗎?
據我所知, 唯一需要顯式簽名的就是消除類型類的歧義。 (正在read . show
的典型示例。show。)還有其他我沒有想到的情況嗎?
(我知道,如果您超越Haskell 2010,會有很多例外情況。例如,GHC永遠不會推斷N級類型。但是N級類型是語言的擴展,不是官方標准的一部分[尚未]。 )
通常,多態遞歸需要類型注釋。
f :: (a -> a) -> (a -> b) -> Int -> a -> b
f f1 g n x =
if n == (0 :: Int)
then g x
else f f1 (\z h -> g (h z)) (n-1) x f1
(來源:帕特里克·庫索)
注意遞歸調用看起來多么嚴重類型(!):它調用本身帶有五個參數,盡管f
只有4級 ! 然后記住,可以使用c -> d
實例化b
,這會導致出現一個額外的參數。
上面的人為例子計算
f f1 g n x = g (f1 (f1 (f1 ... (f1 x))))
其中f1
被應用了n
次。 當然,有一種編寫等效程序的簡單得多的方法。
如果啟用了MonomorphismRestriction
,則有時需要添加類型簽名以獲得最通用的類型:
{-# LANGUAGE MonomorphismRestriction #-}
-- myPrint :: Show a => a -> IO ()
myPrint = print
main = do
myPrint ()
myPrint "hello"
這將失敗,因為myPrint
是單態的。 您需要取消注釋類型簽名以使其起作用,或禁用MonomorphismRestriction
。
當您將具有約束的多態值放入元組時,元組本身將變為多態並具有相同的約束:
myValue :: Read a => a
myValue = read "0"
myTuple :: Read a => (a, String)
myTuple = (myValue, "hello")
我們知道,約束影響的元組的第一部分,但不影響第二部分。 不幸的是,類型系統不知道這一點,如果您嘗試這樣做,將會抱怨:
myString = snd myTuple
即使直覺上會期望myString
只是一個String
,類型檢查器仍需要專門化類型變量a
並確定約束是否真正得到滿足。 為了使該表達式起作用,需要注釋snd
或myTuple
的類型:
myString = snd (myTuple :: ((), String))
可以肯定,您可以在Haskell中推斷類型。 換句話說,編譯器可以計算出所需的類型。
但是,在Haskell中,也存在多態類型類,根據返回類型,函數以不同的方式起作用。 這是Monad類的示例,盡管我還沒有定義所有內容:
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
fail :: String -> m a
我們給了很多帶有類型簽名的功能。 我們的工作是為可以視為Monad的不同類型進行實例聲明,例如Maybe t
或[t]
。
看一下這段代碼-它不能像我們期望的那樣工作:
return 7
那是Monad類的一個函數,但是因為有多個Monad,所以我們必須指定所需的返回值/類型,否則它會自動成為IO Monad。 所以:
return 7 :: Maybe Int
-- Will return...
Just 7
return 6 :: [Int]
-- Will return...
[6]
這是因為[t]
和Maybe
都已在Monad類型類中定義。
這是另一個示例,這一次來自隨機類型類。 此代碼引發錯誤:
random (mkStdGen 100)
因為random
返回Random
類中的某些內容,所以我們必須使用想要的StdGen
對象StdGen
定義想要返回的類型:
random (mkStdGen 100) :: (Int, StdGen)
-- Returns...
(-3650871090684229393,693699796 2103410263)
random (mkStdGen 100) :: (Bool, StdGen)
-- Returns...
(True,4041414 40692)
在網上學習Haskell可以找到所有這些內容,盡管您需要做一些長時間的閱讀。 我幾乎100%地確定,這是唯一需要類型的時間。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.