Вы можете получить немного дальше, если вы добавите inline
(что является обязательным требованием для использования статического ограничения члена) и переименовать статическую переменную от 'a
до ^a
(которая является синтаксисом, используемым параметрами статически разрешенных типов) и удалить явную спецификацию ограничений. Компилятор будет пытаться определить тип ограничений, основанный на коде (что делает его немного более полезной):
let inline updateMean (newObservation : ^a) (currentMean : ^a)
(currentNumberOfRecords : int) =
(newObservation + (currentMean * (currentNumberOfRecords |> float32)))/
(float32 (1 + currentNumberOfRecords))
Однако, это все еще не работает, потому что вы ограничивая currentMean
в float32
- в общий, компилятор требует, чтобы оба параметра оператора имели один и тот же тип. Вы можете сохранить currentNumberOfRecords
как значение одного и того же типа - то только хитрая часть добавляет один, что может быть сделано с помощью LanguagePrimitives.GenericOne
:
let inline updateMean newObservation currentMean currentNumberOfRecords =
(newObservation + (currentMean * currentNumberOfRecords))/
(LanguagePrimitives.GenericOne + currentNumberOfRecords)
Это работает хорошо, но я бы, вероятно, использовать несколько иной подход и сохранить общую сумму вместе с общим количеством (а затем просто разделить их, чтобы получить среднее значение - это, вероятно, имеют лучшие численные свойства, как вы избежать повторного округления):
let inline updateState (currentSum, currentCount) newObservation =
(currentSum + newObservation, currentCount + 1)
let inline currentMean (currentSum, currentCount) =
LanguagePrimitives.DivideByInt currentSum currentCount
хитрость заключается в том, чтобы использовать операции с LanguagePrimitives module и пусть компилятор F # определяет ограничения типа automaticall y (потому что они довольно уродливы).