没有ScopedTypeVariables的外部绑定类型声明

时间:2012-12-11 21:13:45

标签: haskell

我有以下工作定义:

{-# LANGUAGE ScopedTypeVariables #-}
module Control.Retry where

import Prelude hiding (catch)
import Control.Exception
import Control.Concurrent

retrying [] action = action 
retrying (i:is) action = catch action processError
  where 
    processError (e :: IOException) = threadDelay i >> retrying is action

出于好奇,我想知道如何在不使用ScopedTypeVariables编译指示的情况下重新实现这一点,或者我是否可以,以及processError的推断类型声明实际上是什么,因为指定{ {1}}使其无法编译。

3 个答案:

答案 0 :(得分:7)

另一种选择,可能比asTypeOf更清洁:

retrying [] action = action 
retrying (i:is) action = catch action processError                                                                                                                                
  where
    processError e = threadDelay i >> retrying is action
      where
        _ = e :: IOException

不确定这是否是惯用的;我刚刚完成它并且有效。

答案 1 :(得分:6)

如果您想避免ScopedTypeVariables,您大部分时间都可以使用asTypeOf

retrying [] action = action 
retrying (i:is) action = catch action processError
  where 
    processError e = snd (e `asTypeOf` (undefined :: IOException), threadDelay i >> retrying is action)

undefined :: IOException是表达式类型签名,标准允许这样做。 asTypeOf要求例外eIOException

我希望ScopedTypeVariables在这里。

使用

retrying :: [Int] -> IO a -> IO a

processError的类型推断为

processError :: IOException -> IO a

这里的aretrying的签名中的类型变量相同。但是,在没有ScopedTypeVariables扩展名的情况下,不能在Haskell中指定该类型,因为写下签名中的类型变量默认是普遍量化的。

答案 2 :(得分:2)

这个怎么样:

retrying [] action = action 
retrying (i:is) action = catch action $ processError $
                         threadDelay i >> retrying is action
  where
    processError :: IO a -> IOException -> IO a
    processError foo e = foo

基本上,这会解决执行processError :: IOException -> IO a的问题,其中a是通用的,而不是与封闭函数中的a相同,通过参与在其中键入a,以便将其绑定到封闭函数中的类型。