如何在fsharp中使用变量参数绑定外部函数?

时间:2015-03-10 10:53:44

标签: f# extern ncurses

在Ubuntu服务器14.04中安装Fsharp和Mono之后,我正在尝试使用NCurses。我让自己受到几个C#项目的启发。我陷入了以下问题。

/usr/include/ncurses.h中的printw函数定义如下:

extern NCURSES_EXPORT(int) printw (const char *,...)

目标是我可以用以下方式调用:

printw("Hello world")

那么如何在fsharp中为此创建一个extern绑定?请注意,它是“......”,它给我带来了问题..

我已经尝试了一些不起作用的东西:

[<DllImport ("libncurses.so.5")>]
extern int printw(string s, [<ParamArray>] obj[] args)

它编译,但测试结果为:

bindings.printw("Hello world!")
----------------^^^^^^^^^^^^^^

/home/12345/fcurses/stdin(11,17): error FS0001: This expression was expected to have type
    string * obj []
but here has type
    string

根据Parameter Arrays部分,只有方法可以有参数数组。如果我将extern分成一个带有伴随方法的静态extern(受到this post的答案的启发),那么extern仍然被用作一个值,而不是一个方法,所以这里也没有参数数组。 / p>

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

一种不可思议的做法是为你想要传递给函数的每个参数组合创建一个绑定。例如,使用printf,您可以执行以下操作:

open System
open System.Runtime.InteropServices

[<DllImport ("msvcrt40.dll", EntryPoint = "printf")>]
extern Int32 printfInt32 (String format, Int32 arg1)

[<DllImport ("msvcrt40.dll", EntryPoint = "printf")>]
extern Int32 printfString (String format, [<MarshalAs (UnmanagedType.LPStr)>] String arg1)

[<DllImport ("msvcrt40.dll", EntryPoint = "printf")>]
extern Int32 printfInt32String (String format, Int32 arg1, [<MarshalAs (UnmanagedType.LPStr)>] String arg2)


printfInt32 ("%d\n", 42) |> ignore
printfString ("%s\n", "Testing, testing...") |> ignore
printfInt32String ("Number is %d and string is \"%s\"!", 167, "SPARTA") |> ignore

所以在你的情况下它看起来像(未经测试):

[<DllImport ("libncurses.so.5", EntryPoint = "printw")>]
extern Int32 printwInt32(String format, Int32 arg1)

printwInt32 ("%d", 102) |> ignore

真正的解决方案是使用mkrefany IL instruction (see III.4.19 mkrefany),这是F#编译器*不支持的,只能通过C#编译器中的hidden keyword支持。

More information on Bart de Smet's blog.

*您可以使用inline IL code让F#编译器以某种方式发出mkrefany ......