Краткий ответ: замените ваши mutable
параметры на ref
.
У TA-Lib очень неудачный API: эти надоедливые out
-параметры (известны в F # как byref
) они всегда создают проблемы. В этом случае они не могут быть частью общего экземпляра типа c.
Вот гораздо более короткий пример. Возьмем старый добрый 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
. И они запрещены в общем c экземпляре. Неудача.
Но надежда есть!
Ключевое слово mutable
- это только один из двух способов сделать изменяемые ячейки в F #. Другой способ - ref
:
let x = ref 0 // Initialization
printfn "%d" !x // Prints "0"
x := 42 // Mutation
printfn "%d" !x // Prints "42"
Это старая школа, предшествующая mutable
, реализованная как библиотека (в отличие от языковой конструкции), и в большинстве случаев mutable
лучше. Но это не один из таких случаев!
Оказывается, что:
- В отличие от true. NET CIL
out
-параметры, ref
ячейки могут быть частью c экземпляр просто отлично. Потому что, с точки зрения. NET, они не являются чем-то особенным - просто другой класс. - У компилятора F # есть специальный соус для них: когда ожидаемый тип -
ref
, но вы пытаясь передать функцию с out
-параметром на своем месте, компилятор автоматически сгенерирует для вас какой-нибудь код переноса.
Итак, вооружившись этим знанием, вы можете изменить 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