【问题标题】:How to catch a Haskell exception that is thrown in a Haskell callback function called by a C function?如何捕获在 C 函数调用的 Haskell 回调函数中引发的 Haskell 异常?
【发布时间】:2015-06-25 23:36:32
【问题描述】:

有什么好的方法可以捕获一个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 中捕获。 我怎样才能使这种代码运行良好?

【问题讨论】:

标签: haskell exception ffi


【解决方案1】:

您必须手动执行此操作,如下所示:

  • 在调用try的Haskell代码中包装你的回调函数,然后将生成的Either SomeException ()序列化为你可以从C处理的格式(你可以使用StablePtr作为SomeException,但是关键是你需要以某种方式处理Either)。

  • 您的 C 代码调用回调的位置,检查结果是否为 Left exn,如果是,则将错误传播到 C 代码的顶层,并在此过程中适当地释放资源。这一步是非机械的,因为 C 没有异常。

  • 在 C 代码的顶层,重新序列化异常或结果并在 Haskell 函数中读取它,该函数包装对 C 代码的调用,引发异常或根据需要返回结果。

我不知道有任何这样的程序示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-25
    • 2020-11-27
    • 1970-01-01
    • 1970-01-01
    • 2017-01-23
    • 2022-10-01
    • 2013-12-02
    相关资源
    最近更新 更多