在Haskell中删除对象时调用函数

Calling a function at object deletion in Haskell

本文关键字:调用 函数 对象 删除 Haskell      更新时间:2023-10-16

我正在为一个c++类编写一个Haskell包装器。我决定将其表示为Haskell数据结构,其中包含指向c++中的类实例的指针(Foreign.Ptr)。差不多就是这样。

在c++:

class MyClass {
public:
    double my_method();
    // ...
};
extern "C" MyClass* cpp_new_MyClass() {
    return new MyClass();
}
extern "C" double cpp_my_method(MyClass *obj) {
    return obj->my_method();
}
在Haskell:

Data MyClass = MyClass (Ptr ())
foreign import ccall "cpp_new_MyClass" cppNewMyClass :: Ptr () 
foreign import ccall "cpp_my_method" cppMyMethod :: Ptr () -> Double
mkMyClass :: MyClass
mkMyClass = MyClass cppNewMyClass
myMethod :: MyClass -> Double
myMethod (MyClass ptr) = cppMyMethod ptr

问题是,我不知道如何正确地实现MyClass删除。在某些情况下,Haskell垃圾收集器将删除MyClass对象,但它不会触发c++中的MyClass*内存释放。我该如何解决这个问题?

我知道ForeignPtr,但它使用IO monad,这是不满意的,因为我希望包装的数据结构的行为完全像一个正常的Haskell数据结构,而不需要显式分配/释放内存或IO monad。

“它使用IO monad,这是不满意的,因为我希望包装的数据结构的行为完全像一个普通的Haskell数据结构”

你当然知道,但不幸的是这是不可能的。外国";functions”总是可以做一些在Haskell中不可能做的有趣的事情;类型系统没有办法查看并阻止它。

这个困境是我们有unsafePerformIO的唯一(!)原因,实际上你的是一个很好的例子,一个有效的应用程序。

我自己还没有这样做,但是你的代码应该像下面这样:

extern "C" void cpp_delete_MyClass(MyClass* obj) {
    delete obj;
}
foreign import ccall "cpp_new_MyClass" cppNewMyClass :: IO (Ptr ())
foreign import ccall "&cpp_delete_MyClass" cppDeleteMyClass :: FunPtr (Ptr () -> IO ())
data MyClass = MyClass (ForeignPtr ())
mkMyClass :: MyClass
mkMyClass = unsafePerformIO $ do
   newObj <- cppNewMyClass
   fPtr <- newForeignPtr cppDeleteMyClass newObj
   return $ MyClass fptr

我不太确定这些FunPtr s,希望有人能评论一下…