有没有什么好方法可以捕获一个haskell异常,它被c函数调用的haskell回调函数抛出?
例如,让我有一个简单的c函数,它只调用给定的回调函数,
void callmeback ( void (*callback) () ) {
callback ();
}
和通过ffi使用此功能的haskell代码。
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ForeignFunctionInterface #-}
module Main (main) where
import Foreign
import Control.Exception
import Data.Typeable
foreign import ccall safe "wrapper"
mkCallback :: IO () -> IO (FunPtr (IO ()))
foreign import ccall safe "callmeback"
callmeback :: FunPtr (IO ()) -> IO ()
data AnError = AnError String deriving (Show, Eq, Typeable)
instance Exception AnError
callback :: IO ()
callback = throwIO $ AnError "Catch me."
callMeBack :: IO () -> IO ()
callMeBack f = do fp <- mkCallback f
callmeback fp
main = do callMeBack callback `catch`
(\ e -> do putStrLn $ show (e :: AnError)
putStrLn "I caught you." )
putStrLn "-- Happy end."
执行结果(用GHC 7.8.2编译)如下:
% ./Catch
Catch: AnError "Catch me."
因此callback
中出现的异常似乎无法在main
中捕获。
如何才能使这种代码正常工作?
答案 0 :(得分:4)
您必须手动执行此操作,如下所示:
在调用try
的Haskell代码中包装回调函数,然后将生成的Either SomeException ()
序列化为可以从C处理的格式(可以使用StablePtr
SomeException
,但重点是你需要以某种方式处理Either
。
在C代码调用回调的地方,检查结果是否为Left exn
,如果是,则将错误传播到C代码的顶层,并在适当的时候释放资源。此步骤是非机械的,因为C没有例外。
在C代码的顶层,重新序列化异常或结果,并在Haskell函数中读取它,该函数包装您对C代码的调用,引发异常或返回结果。
我不知道任何一个程序的例子。