Haskell 不带ScopedTypeVariables的外部绑定类型声明
我有以下工作定义:Haskell 不带ScopedTypeVariables的外部绑定类型声明,haskell,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
{-# 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
pragma的情况下重新实现它,或者我是否可以,以及processError
的推断类型声明实际上是什么,因为指定processError::IOException->IO a
会使其无法编译。如果要避免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
与
processError
的类型推断为
processError :: IOException -> IO a
此处的
a
与重试的签名中的类型变量相同。但是,如果没有扩展名ScopedTypeVariables
,则不能在Haskell中指定该类型,因为默认情况下,写下的签名中的类型变量是通用量化的。另一个选项,可能比aTypeof更简洁:
retrying [] action = action
retrying (i:is) action = catch action processError
where
processError e = threadDelay i >> retrying is action
where
_ = e :: IOException
不确定这是否是惯用语;我刚刚编造出来,效果很好。这个怎么样:
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
的参数,以便将其绑定到封闭函数中的类型。谢谢。但是processError
的类型签名呢?它如何将操作的类型绑定到外部函数?processError
没有ScopedTypeVariables
就不能有类型签名。在其推断类型中,使用封闭作用域数据中的action
将其结果类型指定为IO,无论重试的结果类型是什么。因此,给定重试::[Int]>ioa->ioa
,推断出的processError
类型是processError::IOException->ioa
。但是没有STV你就写不下这种类型。出于好奇,lambda演算数学家会用什么花哨的名字来描述这种把戏?@Tarrasch我不知道它是否广泛到可以命名。我主要在quickcheck测试的上下文中看到过这种情况,在这里你可以看到成语where\u types=(foo::a,bar::B)
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