首页 > 解决方案 > 如何判断包装在 SomeException 中的异常是否是类的实例?

问题描述

我想为自定义异常类型实现一个类实例,然后在该类型的处理程序中使用该类实例。下面的代码显示了我正在尝试做的事情;我想找到适合“???”的东西。

这是棘手的部分:我想在不引用MyExceptionhandler 的情况下执行此操作。例如,使用fromExceptionorData.Typeable.cast将不起作用。原因是处理程序将存在于一个包中,而异常类型将存在于另一个包中。我希望能够编写额外的包来定义它们自己的异常类型和MyClass实例,并且我希望处理程序能够在不知道异常类型是什么的情况下使用这些包。

我知道有很多关于“判断 X 是否是 Y 的实例的方法”的问题,但我无法在SomeException包装器存在的情况下找到一个工作。(例如:https://wiki.haskell.org/GHC/AdvancedOverlap。

{-# LANGUAGE ScopedTypeVariables #-}

module Main where

import Control.Exception

data MyException = MyException
  deriving Show
instance Exception MyException

class MyClass a where
  useMyClass :: a -> String

main :: IO ()
main = catch (throwIO MyException) $ \(SomeException e) -> do
  if ??? then (putStrLn ("Used custom exception class: " <> useMyClass e))
  else (putStrLn ("Showing exception: " <> show e))

标签: haskell

解决方案


做不到。但是,您可以使开放包装器存在:

data SomeMyClass where SomeMyClass :: MyClass a => a -> SomeMyClass

然后,您可以要求所有用户抛出 a而不是他们的自定义类型,如有必要SomeMyClass,首先通过调用构造函数进行转换。SomeMyClass

catches (throwIO (SomeMyClass MyException))
    [ Handler (\(SomeMyClass e) -> putStrLn ("used custom exception: " <> useMyClass e))
    , Handler (\(SomeException e) -> putStrLn ("showing exception: " <> show e))
    ]

推荐阅读