用.NET GUI创建一个Haskell应用程序

我想用.NET gui创建一个Haskell应用程序。 我想使用cabal作为我的构建工具来利用它的包管理等。我认为Haskell部分应该是调用.NET代码的可执行文件,如下所示:

  • 这避免了必须手动初始化Haskell RTC,如下所述:http://www.haskell.org/ghc/docs/7.0.3/html/users_guide/win32-dl​​ls.html

  • cabal无法轻松生成Windows dlls:http://www.haskell.org/haskellwiki/Cabal/Developer-FAQ#Building_DLLs__with_Cabal

  • 我发现创建一个使用hs-dotnet调用.NET的Haskell可执行程序相当简单,但我还需要使用我的GUI代码才能回调Haskell。 我希望使用Haskell的“外部导出”命令来实现这一点,然后通过.NET本地互操作调用此导出的函数。 然而,“外部输出”函数似乎并没有在可执行文件中创建一个入口点,当我对生成的可执行文件执行dumpbin /EXPORTS时,我看不到入口点。 我不确定这是否是因为GHC只通过-shared开关创建dll时创建入口点,或者cabal是否添加了禁止入口点创建的标志。

    所以我想问题是我如何强制GHC在我的Windows可执行文件中创建入口点? 或者我会更好地使用.NET可执行文件,通过必要的步骤创建一个Haskell dll与cabal并手动初始化Haskell RTC?


    我通常通过将回调函数作为函数指针来解决这个问题。 例如,我有一个应用程序,按下按钮需要回调Haskell(我使用Cocoa,但名称非常相似)。

    首先,我继承了一个NSButton对象,并为我的新ButtonC类提供了一个类型为void(*onClickCallback)()的私有成员。 我还声明了一个函数void setClickCallback(ButtonC *button, void(*callback)()); 实现你的子类,以便每当按钮被点击时,函数指针被调用。 在.Net中,可能有一个聪明的方式来与代表做这件事(自从我使用.Net以来已经有一段时间了)。

    接下来,我的Haskell绑定看起来像这样(省略了一些代码):

    module Foreign.Button where
    
    data ButtonObj
    type ButtonPtr = ForeignPtr ButtonObj
    
    foreign import ccall unsafe "setClickCallback"
      c_setClickCallback :: Ptr ButtonObj -> FunPtr (IO ()) -> IO ()
    
    foreign import ccall "wrapper"
      makeClickCallback :: IO () -> IO (FunPtr (IO ()))
    
    buttonSetCallback :: ButtonPtr -> FunPtr (IO ()) -> IO ()
    buttonSetCallback btn cb =
        withForeignPtr btn $ p -> c_setClickCallback p cb
    
    buttonNew :: IO ButtonPtr
    buttonNew = ...
    

    类型的现在的Haskell数据IO ()可以被包裹在一个FunPtr并通过与GUI buttonSetCallback 。 无论何时按下按钮,都会执行IO ()操作。

    createButton :: IO ButtonPtr
    createButton = do
        btn <- buttonNew
        let buttonClicked = print "The button was clicked!"
        btnCallback <- makeClickCallback buttonClicked
        buttonSetCallback btn btnCallback
        return btn
    

    FunPtr的是,他们不是垃圾收集。 您需要在完成后手动释放它们,否则会发生内存泄漏。 一个好的做法是不要共享FunPtr ,也不要在Haskell方面保留对它们的引用。 这样你的对象就可以将FunPtr作为清理的一部分。 这需要对Haskell( freeFunPtr函数)进行另一次回调,该回调应该在所有对象之间共享,并且只有当您的可执行文件终止时才会释放它。

    链接地址: http://www.djcxy.com/p/58427.html

    上一篇: Creating a Haskell application with a .NET GUI

    下一篇: How to setup build/deployment for .net project on Jenkins