F# - 如何将数组转换为 nativeptr<double>

F# - How to convert array into nativeptr<double>

我需要与一些低级 C/FORTAN 库互操作。该库要求我提供一个回调函数,它在 C# 中具有以下签名:

public static class Interop
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public unsafe delegate void F(
        ref int neq,
        ref double t,
        double* y,
        double* yDot);
}

变量 neq 包含数组 yyDot 的长度。外部库将提供指向这些数组的第一个元素的指针。

我可以轻松创建 F# 互操作以供该库使用,例如:

let private f (neq : byref<int>, t : byref<double>, x : nativeptr<double>, dx : nativeptr<double>) : unit =

    for i in 0 .. (neq - 1) do
        NativePtr.set dx i (NativePtr.get x i)


let createInterop() = Interop.F(fun n t y dy -> f(&n, &t, y, dy))

有效,我可以看到正在调用该函数并执行某些操作。

现在,我想编写一个测试,以确保我创建的互操作正常工作。

let interopTest() =
    let neq = 10
    let t = 0.0
    let (x : double[]) = Array.zeroCreate n
    let (dx : double[]) = Array.zeroCreate n
    let interop = createInterop()

    // Call the interop. ! DOES NOT COMPILE !
    do interop.Invoke(ref neq, ref t, x, dx)

    // Verify the results.

无论尝试什么,对 interop.Invoke 的调用都无法编译。对于上面的代码,它在 xdx 处失败并显示消息:

[FS0001] This expression was expected to have type
    'nativeptr<float>'    
but here has type
    'double []'

我可以将 neqt 声明为可变的,然后像这样调用互操作:interop.Invoke(&neq, &t, ...。那没有区别。但是,使用例如&dx.[0] 产生相同的编译器错误。

我需要将指向数组 xdx 的第一个元素的指针传递给互操作函数。不幸的是,搜索如何在 F# 中将数组转换为 nativeptr 没有产生任何有用的结果。

谢谢。

这就是“如何在 F# 中将数组转换为 nativeptr”的方法:

open Microsoft.FSharp.NativeInterop  
    
let private f (neq : byref<int>, t : byref<double>, x : nativeptr<double>, dx : nativeptr<double>) : unit =

    for i in 0 .. (neq - 1) do
        NativePtr.set dx i (NativePtr.get x i)

let createInterop() = fun n t y dy -> f(&n, &t, y, dy))

let interopTest() =
    let n = 10
    let t = 0.0
    let (x : double[]) = Array.zeroCreate n
    let (dx : double[]) = Array.zeroCreate n

    let tx = NativePtr.ofNativeInt<double> x     
    let tdx = NativePtr.ofNativeInt<double> dx     
   
    let interop = createInterop()

    // Call the interop. Does compile but does not call your c# interop
    // but does create the correct nativeptr(s)
    interop n  t tx tdx

    // Verify the results.

更新:

显然这对 OP 不起作用,但 txtdx 都产生相同的正确类型,无论哪种方式,在 VS Code 中,至少对我而言。无论如何,这显示了另一种有趣的做同样事情的方法,也许其他人可能会发现一个有效而另一个无效?

let interopTest() =
    let n = 10
    let t = 0.0
    let (x : double[]) = Array.zeroCreate n
    let (dx : double[]) = Array.zeroCreate n

    let tx = fixed &x.[0]    // val tx: nativeptr<double>
    let tdx = fixed &dx.[0]  // val tdx: nativeptr<double>

      
    let interop = createInterop()

    // Call the interop.
    do interop.Invoke(ref n, ref t, tx, tdx)

    // Verify the results.