调用.NET Haskell的功能(Call a Haskell function in .NET)

2019-07-20 03:08发布

我想用一个Haskell函数具有以下类型:: string -> string从C#程序。

我想使用HS-dotnet的弥补两全其美。 作者声称,这是可能的,但没有提供这种情况下的样本。 提供的唯一样本是使用.NET从哈斯克尔之一。

是否有这种使用的样品,或如何使用它? (我用.net反射的桥接组装,但我不明白的事情。)

Answer 1:

当你的工作方式,这是值得注意的,你遇到的dificulties是你自己做的不幸(而不是在错误GHC ):((以下假定构建DLL时所使用的GHC的文件和你的RTS在DLL主装)。

在第一部分,你目前的内存分配问题,有处理这一点,这是不安全的代码更容易C#原生方式。 在不安全的代码分配的任何内存将在托管堆中外进行分配。 因此,这将否定对C挂羊头卖狗肉的需求。

第二部分是使用在C#中的LoadLibrary的。 究其原因的P / Invoke无法找到出口很简单:在你的Haskell代码您使用申报出口声明ccall ,而在.NET中的标准命名约定是stdcall ,这也是标准的Win32 API调用。

stdcallccall有不同的名称manglings和resposibilities在争论的清理期限。

特别是,GHC / GCC将陆续出口“wEval”,而.NET在默认情况下会寻找“_wEval @ 4”。 现在,这是很容易解决,只需添加CallingConvention = CallingConvention.Cdecl。

但是使用这个调用约定的调用者需要清理堆栈。 所以,你需要额外的工作。 现在,假设你只打算使用在Windows操作系统上,只是出口的哈斯克尔功能stdcall 。 这使得您的.NET代码更简单,使

[DllImport("foo.dll", CharSet = CharSet.Unicode)]
public static extern string myExportedFunction(string in);

几乎是正确的。

什么是正确的将是例如

[DllImport("foo.dll", CharSet = CharSet.Unicode)]
public unsafe static extern char* myExportedFunction([MarshalAs(UnmanagedType.LPWStr)]string in);

没有更多需要调用LoadLibrary等。 并得到一个托管字符串只是用

String result = new String(myExportedFunction("hello"));

例如。

有人会认为,

[DllImport("foo.dll", CharSet = CharSet.Unicode)]
[return : MarshalAs(UnmanagedType.LPWStr)]
public static extern string myExportedFunction([MarshalAs(UnmanagedType.LPWStr)]string in);

应太,但它不会因为现Marshaller预计将所配CoTaskMemAlloc String和将调用CoTaskMemFree它和崩溃

如果你想在管理土地留完全,你总是可以做

[DllImport("foo.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr myExportedFunction([MarshalAs(UnmanagedType.LPWStr)]string in);

然后它可以被用来作为

string result = Marshal.PtrToStringUni(myExportedFunction("hello"));

工具可以在这里找到http://hackage.haskell.org/package/Hs2lib-0.4.8

更新 :有一定程度的一大疑难杂症,我已经最近发现。 我们必须记住,在.NET中的字符串类型是不可改变的。 因此,当编组发送给了Haskell代码,我们得到的CWString存在的原件及复印件。 我们必须释放此。 当GC在C#中执行它不会影响该CWString,这是一个副本。

但问题是,当我们在Haskell代码中解放出来,我们不能使用freeCWString。 指针没有与C(MSVCRT.DLL)的ALLOC分配。 有三种方式(即我所知道的)来解决这个问题。

  • 调用哈斯克尔功能时使用的char *在你的C#代码,而不是字符串。 然后,您有指针,当你调用返回,或初始化指针使用自由固定 。
  • 进口CoTaskMemFree在Haskell和自由在Haskell指针
  • 使用StringBuilder而不是字符串。 我不完全知道这一个,但这个想法是,既然StringBuilder的是作为本机的指针来实现,现Marshaller只是通过这个指针到您的Haskell代码(也可顺便说一句更新)。 当GC在调用返回后执行,StringBuilder的应该被释放。


Answer 2:

正如更新,我已经做了Haskell的DLL和弥合两个世界这种方式解决了这个问题。

如果你想走上相同的道路,一定要使用::CoTaskMemAlloc为.NET世界的分配数据。 另一种疑难杂症是使用调用LoadLibrary / GetProcAdress,对于一些未知的原因,进口不会自动工作,他们应该是这样。 更深入的文章 ,以帮助呼吁从.NET哈斯克尔。



Answer 3:

你当然可以从C中的至少叫哈斯克尔 - 你在Haskell的文件中使用“外贸出口”,并GHC生成的C头,然后可以导入和使用来自C.调入哈斯克尔

我从来没见过这样的.NET绑定完成的 - 所以我认为这是最好问这两个作者 - Sigbjorn - 和Haskell的咖啡厅@的例子。



Answer 4:

如果你想在.NET Haskell中,只使用F# 。



文章来源: Call a Haskell function in .NET