F # Единицы измерения, проблемы с универсальностью

(Я все еще banging с единицами измерения в F #)

У меня проблема с созданием «общих» функций, которые принимают «типизированные» числа с плавающей запятой.

Следующий класс макета предназначен для отслеживания совокупной ошибки положения на основе фактора «c». Компилятору не нравится, когда я говорю 0. ‹'A> в теле типа (« Неожиданный параметр типа в литерале единицы измерения »).

///Corrects cumulative error in position based on s and c
type Corrector(s_init:float<'a>) =
    let deltaS ds c = sin (ds / c) //incremental error function

    //mutable values
    let mutable nominal_s = s_init
    let mutable error_s = 0.<'a>  //<-- COMPILER NO LIKE

    ///Set new start pos and reset error to zero
    member sc.Reset(s) = 
        nominal_s <- s
        error_s <- 0.<'a>  //<-- COMPILER NO LIKE

    ///Pass in new pos and c to corrector, returns corrected s and current error    
    member sc.Next(s:float<'a>, c:float<'a>) = 
        let ds = s - nominal_s //distance since last request
        nominal_s <- s   //update nominal s
        error_s <- error_s + (deltaS ds c) //calculate cumulative error
        (nominal_s + error_s, error_s) //pass back tuple

Еще один связанный с этим вопрос, как мне кажется, все еще связан с «общими» функциями.

В следующем коде я пытаюсь создать функцию, которая будет принимать #seq любого типа с плавающей запятой и применять ее к функции, которая принимает только «ванильные» поплавки. В третьей строке отображается ошибка «ограничения значения». , и я не вижу выхода. (Удаление символа # решает проблему, но я бы не хотел писать то же самое для списков, последовательностей, массивов и т. Д.)

[<Measure>] type km //define a unit of measure
let someFloatFn x = x + 1.2 //this is a function which takes 'vanilla' floats
let MapSeqToNonUnitFunction (x:#seq<float<'a>>) = Seq.map (float >> someFloatFn) x
let testList = [ 1 .. 4 ] |> List.map float |> List.map ((*) 1.0<km>)
MapSeqToNonUnitFunction testList

person Benjol    schedule 20.01.2009    source источник


Ответы (2)


Вы можете изменить первый "компилятор не нравится" на

let mutable error_s : float<'a> = 0.0<_>

и компилятору, кажется, это нравится.

Что касается второго вопроса, я не вижу такой же ошибки, как вы, и это

[<Measure>] type km 
//define a unit of measure
let someFloatFn x = x + 1.2 //this is a function which takes 'vanilla' floats
let MapSeqToNonUnitFunction (x:seq<float<_>>) = Seq.map (float >> someFloatFn) x
let testList = [ 1 .. 4 ] |> List.map float |> List.map ((*) 1.0<km>)
let testList2 = testList :> seq<_>
let result = MapSeqToNonUnitFunction testList2
printfn "%A" result

компилируется для меня (хотя повышение до seq ‹_> немного раздражает, я не уверен, есть ли простой способ избавиться от него или нет).

Кроме того, я думаю, что по соглашению параметры единиц измерения называются 'u,' v, ..., а не 'a,' b, ...

person Brian    schedule 20.01.2009
comment
Я оставлю это как ответ, поскольку он ответил на две трети моего вопроса. И спасибо за напоминание о соглашении об именах. Я бы тоже хотел избежать апкаста. - person Benjol; 17.02.2009

Единицы измерения нельзя использовать в качестве параметров типа. Это связано с тем, что компилятор стирает их во время компиляции. Этот вопрос очень похож: F # Единицы измерения - «подъем» значений до плавать ‹something›

person Robert    schedule 20.01.2009
comment
Я тоже спросил об этом, должно быть, я немного медлил с восприятием! Полагаю, это означает, что у меня есть два варианта: либо я использую заданную единицу, либо передаю нулевое значение? - person Benjol; 20.01.2009
comment
Я не уверен, что понимаю, что вы имеете в виду, что нельзя использовать в качестве параметров типа, потому что это работает: let fn (a: float ‹'a›) (b: float ‹' a›) = a * b - person Benjol; 20.01.2009