2014-06-24 18 views
4

(道歉,如果我的術語是錯誤的)。如何指定內聯類型中使用的類型變量,是否與函數定義中使用的類型變量相同?

我想寫處理異常的包裝功能:如果給定IO動作拋出,則返回Nothing(當然是IO上下文中),但如果給定IO行動成功,則返回Just v

tryMaybe :: IO a -> IO (Maybe a) 
tryMaybe action = do 
    result <- (try action) :: IO (Either SomeException a) 
    return $ case result of 
     Left _ -> Nothing 
     Right v -> Just v 

這將導致編譯器錯誤消息:

Couldn't match type `a' with `a1' 
     `a' is a rigid type variable bound by 
      the type signature for tryMaybe :: IO a -> IO (Maybe a) 
      at src/Database.hs:33:13 
     `a1' is a rigid type variable bound by 
      an expression type signature: IO (Either SomeException a1) 
      at src/Database.hs:35:15 
    Expected type: IO a1 
     Actual type: IO a 
    In the first argument of `try', namely `action' 

我猜測,在第一線的類型變量a是不一樣的,在第三行a - 他們只是恰巧在源代碼中具有相同的名稱,並且編譯器在錯誤消息中將其重命名爲a1

那麼,我如何告訴Haskell這些是相同的類型呢?

+4

您是否試過'ScopedTypeVariables'? – bheklilr

+1

相關解釋在這裏:http://stackoverflow.com/questions/15800878/scoped-type-variables-require-explicit-foralls-why – stusmith

回答

10

您需要啓用ScopedTypeVariables擴展和變化的頂級函數的類型簽名與forall a .開始:

{-# LANGUAGE ScopedTypeVariables #-} 

... 

tryMaybe :: forall a . IO a -> IO (Maybe a) 
... 

forall語法帶來的類型變量a到範圍爲整個身體的tryMaybe,而不僅限於默認的類型簽名。這主要是歷史反常現象,而不是故意的設計。

+6

啊哈是的,它排序。我知道GHC試圖在這裏保持與Haskell 98的向後兼容性,但是我會想到一個關於類型變量陰影的警告(如果這是正確的術語),加上調查語言擴展的提示,可能對像我這樣的新手有所幫助。啊,我生活和學習。非常感謝! – stusmith

+5

@stusmith我認爲影子警告是一個好主意。您應該提交ghc增強權證。 – augustss

+1

提出的GHC票:https://ghc.haskell.org/trac/ghc/ticket/9244 – stusmith