gpt4 book ai didi

f# - 什么是错误 "A type instantiation involves a byref type."以及 F# 中的解决方法是什么

转载 作者:行者123 更新时间:2023-12-04 16:41:15 27 4
gpt4 key购买 nike

我有一些包装 TA-Lib 的代码,很多包装器都非常相似:

let sma (timePeriod: int) (data: float[]) =
let mutable outStartIndex = 0
let mutable outNbElement = 0

let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)

let retCode = Core.Sma(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, smaData)

if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")

let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding smaData



let ema (timePeriod: int) (data: float[]) =
let mutable outStartIndex = 0
let mutable outNbElement = 0
let mutable emaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)

let retCode = Core.Ema(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, emaData)

if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")

let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding emaData

我想做的是创建一个通用函数,我可以在其中传递 TA-Lib 函数来调用。就像是:
let myGenericFunction (timePeriod: int) (data: float[]) TALibFunc =
let mutable outStartIndex = 0
let mutable outNbElement = 0

let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)

let retCode = TALibFunc(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, smaData)

if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")

let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding smaData

但我得到的错误是:

[FS0412] A type instantiation involves a byref type. This is not permitted by the rules of Common IL.



有解决方法吗?我不熟悉这个问题。

最佳答案

简答:更换您的 mutable参数与 ref .

TA-Lib 有一个非常不幸的 API:那些讨厌的 out -parameters(在 F# 中称为 byref ),它们总是会制造麻烦。在这种情况下,它们不能是泛型类型实例化的一部分。

这是一个更短的例子。考虑一个好的老list<T> .我们可以做一个空list<int> :

let noInts = [] : list<int>

但是如果那些 int s 是 byref ?
let noRefs = [] : list< byref<int> >

没有办法- 编译器说。类型实例化涉及 byref 类型。这是 Common IL 的规则所不允许的。对不起。

在您的情况下, myGenericFunction 的最后一个参数是一个 F# 函数。在 F# 中,函数由类型 FSharpFunc<T, R> 表示(其中 T 是参数, R 是结果)。所以你最后一个参数的类型是这样的:
FSharpFunc< int * int * float array * int * byref<int> * byref<int> * float array, int >

看到那两个 byref<int>在那里?那些是 &outStartIndex&outNbElement .并且它们在通用实例化中是被禁止的。倒霉。

但还有希望!
mutable关键字只是在 F# 中创建可变单元格的两种方法之一。另一种方式是 ref :
let x = ref 0     // Initialization
printfn "%d" !x // Prints "0"
x := 42 // Mutation
printfn "%d" !x // Prints "42"

这是一个老派的东西,早于 mutable , 被实现为一个库(而不是语言结构),并且在大多数情况下 mutable更好。但这不是其中之一!

事实证明:
  • 不像真正的 .NET CIL out -参数,ref单元格可以作为通用实例化的一部分就好了。因为,从 .NET 的角度来看,它们没什么特别的——只是另一个类。
  • F# 编译器对它们有特别的帮助:当预期的类型是 ref 时,但你试图传递一个带有 out 的函数-parameter 在它的位置,编译器会自动为你生成一些包装代码。

  • 因此,有了这些知识,您可以修改 myGenericFunction像这样:
    let myGenericFunction (timePeriod: int) (data: float[]) TALibFunc =
    let outStartIndex = ref 0
    let outNbElement = ref 0

    let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)

    let retCode = TALibFunc(0, (data.Length - 1), data, timePeriod, outStartIndex, outNbElement, smaData)

    ...

    然后消费者可以这样称呼它:
    myGenericFunction 42 [|1; 2; 3|] Core.Sma // Wrapping code gets generated here

    关于f# - 什么是错误 "A type instantiation involves a byref type."以及 F# 中的解决方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60405249/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com