如果你看一下catches
的例子:
f = expr `catches` [Handler (\ (ex :: ArithException) -> handleArith ex),
Handler (\ (ex :: IOException) -> handleIO ex)]
看起来catches
定义了一种自定义机制来匹配模式(两种异常类型)。我错了,或者这可以推广到允许我们定义一个函数,该函数可以采用匹配特定模式的lambda函数?
编辑:下面的FYI是渔获量的GHC来源。如果有人能够了解它是如何工作的,那就太棒了。
catches :: IO a -> [Handler a] -> IO a
catches io handlers = io `catch` catchesHandler handlers
catchesHandler :: [Handler a] -> SomeException -> IO a
catchesHandler handlers e = foldr tryHandler (throw e) handlers
where tryHandler (Handler handler) res
= case fromException e of
Just e' -> handler e'
Nothing -> res
答案 0 :(得分:5)
这是Scoped Type Variables GHC扩展工作。点击链接了解更多信息。
基本上,你定义一个关于类型的断言,它必须在模式匹配之前满足。所以,是的,它类似于警卫,但并非完全如此。
这个特定的例子如何运作?深入了解sources of "base" library以了解:
class (Show e) => Exception e where
toException :: e -> SomeException
fromException :: SomeException -> Maybe e
data SomeException = forall e . Exception e => SomeException e
instance Exception IOException where
toException = IOException
fromException (IOException e) = Just e
fromException _ = Nothing
instance Exception ArithException where
toException = ArithException
fromException (ArithException e) = Just e
fromException _ = Nothing
我们发现IOException
和ArithException
是实现类型类Exception
的不同类型。我们还看到toException/fromException
是一种包装/展开机制,允许用户将类型Exception
的值转换为IOException
,ArithException
等类型的值。
所以,我们可以写:
f = expr `catches` [Handler handleArith,
Handler handleIO]
handleArith :: ArithException -> IO ()
handleArith ex = ....
handleIO :: IOException -> IO ()
handleIO ex = ....
假设IOException
发生了。当catchesHandler
处理处理程序列表的第一个元素时,它会调用tryHandler
,调用fromException
。根据{{1}}的定义,tryHandler
的返回类型应与fromException
的参数相同。另一方面,handleArith
的类型为Exception,即 - (IOException ...)。所以,类型以这种方式播放(这不是一个有效的haskell,但我希望你明白我的观点):
e
从fromException :: (IOException ...) -> Maybe ArithException
开始紧接着结果为instance Exception IOException ...
,因此跳过此处理程序。通过相同的推理,将调用以下处理程序,因为Nothing
将返回fromException
。
因此,您已使用(Just (IOException ...))
和handleArith
的类型签名来指定何时调用它们,handleIO
确保以这种方式发生。
如果您愿意,还可以使用范围类型变量约束fromException/toException
定义中handleIO
和handleArith
的类型。可以说,这可以为您提供更好的可读性。
最终确定,Scoped Type Variables不是这里的主要参与者。它们仅用于方便。玩这种技巧的主要机器是f
和朋友。 Scoped Type Variables只允许您使用更接近保护模式的语法。
答案 1 :(得分:1)
case () of
()| foo expr1 -> handleFooCase
| bar expr2 -> handleBarCase
| otherwise -> blah