我有以下工作定义:
{-# 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}}使其无法编译。
答案 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
要求例外e
为IOException
。
我希望ScopedTypeVariables
在这里。
使用
retrying :: [Int] -> IO a -> IO a
processError
的类型推断为
processError :: IOException -> IO a
这里的a
与retrying
的签名中的类型变量相同。但是,在没有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
,以便将其绑定到封闭函数中的类型。