4

我有以下工作定义:

{-# 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

只是出于好奇,我想知道如何在不使用ScopedTypeVariablespragma 的情况下重新实现它,或者我是否可以,以及推断的类型声明processError实际上是什么,因为指定processError :: IOException -> IO a使它无法编译。

4

3 回答 3

7

另一种选择,可能比 asTypeOf 更干净一点:

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

不确定这是否是惯用的;我只是做了它并且它起作用了。

于 2012-12-11T22:01:22.960 回答
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。但是,如果没有扩展,则不能在 Haskell 中指定该ScopedTypeVariables类型,因为写下签名中的类型变量默认情况下是通用量化的。

于 2012-12-11T21:25:44.637 回答
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

基本上,这解决了 do 的问题processError :: IOException -> IO a,其中a是通用的并且与a封闭函数中的不同,方法是接受一个带有类型的参数,a以便将其与封闭函数中的类型联系起来。

于 2012-12-12T08:08:31.637 回答