如何捕获 C 函数调用的 Haskell 回调函数中抛出的 Haskell 异常?
How to catch a Haskell exception that is thrown in a Haskell callback function called by a C function?
有没有什么好的方法可以捕捉到 haskell 异常,它是在 c 函数调用的 haskell 回调函数中抛出的?
例如,让我有一个简单的 c 函数,它只调用给定的回调,
void callmeback ( void (*callback) () ) {
callback ();
}
和一个 haskell 通过 ffi 使用此函数的代码。
{-# 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
中无法捕获。
我怎样才能使这种代码正常工作?
您必须手动执行此操作,如下所示:
将您的回调函数包装在调用 try
的 Haskell 代码中,然后将生成的 Either SomeException ()
序列化为您可以从 C 处理的格式(您可以使用 StablePtr
作为 SomeException
,但关键是您需要以某种方式处理 Either
)。
在您的 C 代码调用回调的位置,检查结果是否为 Left exn
,如果是,则将错误传播到 C 代码的顶层,同时适当释放资源方式。这一步是非机械的,因为 C 没有例外。
在您的 C 代码的顶层,重新序列化异常或结果,并在包装您对 C 代码的调用的 Haskell 函数中读取它,引发异常或根据情况返回结果。
我不知道有任何执行此操作的程序示例。
有没有什么好的方法可以捕捉到 haskell 异常,它是在 c 函数调用的 haskell 回调函数中抛出的?
例如,让我有一个简单的 c 函数,它只调用给定的回调,
void callmeback ( void (*callback) () ) {
callback ();
}
和一个 haskell 通过 ffi 使用此函数的代码。
{-# 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
中无法捕获。
我怎样才能使这种代码正常工作?
您必须手动执行此操作,如下所示:
将您的回调函数包装在调用
try
的 Haskell 代码中,然后将生成的Either SomeException ()
序列化为您可以从 C 处理的格式(您可以使用StablePtr
作为SomeException
,但关键是您需要以某种方式处理Either
)。在您的 C 代码调用回调的位置,检查结果是否为
Left exn
,如果是,则将错误传播到 C 代码的顶层,同时适当释放资源方式。这一步是非机械的,因为 C 没有例外。在您的 C 代码的顶层,重新序列化异常或结果,并在包装您对 C 代码的调用的 Haskell 函数中读取它,引发异常或根据情况返回结果。
我不知道有任何执行此操作的程序示例。