Strip Unit of Measure from array
Asked Answered
A

4

5

I am calling external function requiring float[], but my array is float<m>[]. How could I strip the unit of measure from array?

I need something like the function below, but this does not compile. And I would like to avoid any iterating or duplicating of the array, as float<m> and float values are identical...

let demeasure (arr:float<m>[]): float[] = float[] (arr)
Ania answered 9/7, 2012 at 22:19 Comment(0)
O
4

I believe that a cast to obj, followed by a dynamic cast to float[] would work, e.g.

(arr :> obj) :?> float[]

because there is no runtime representation.

Possibly see also

F# Units of measure - 'lifting' values to float<something>

How to generically remove F# Units of measure

Overvalue answered 9/7, 2012 at 22:26 Comment(0)
H
2

Here's a generic solution for any numeric type, any unit of measure but for Arrays only. If we had Higher Kinds it could be made generic over the container as well:

let inline retype (x: 'T) : 'U = (# "" x: 'U #)

module Array =
    let inline stripUoM (x: '``Num<'M>`` []) =
        let _ = Unchecked.defaultof<'``Num<'M>``> * (LanguagePrimitives.GenericOne : 'Num)
        retype x :'Num []
// Usage

[<Measure>]type m

let x = [|34.0<m>; 9.0<m>; 42.0<m> |] |> Array.stripUoM
// val x : float [] = [|34.0; 9.0; 42.0|]

let y = [|34<m>; 9<m>; 42<m> |] |> Array.stripUoM
// val y : int [] = [|34; 9; 42|]
Homocyclic answered 2/7, 2020 at 6:11 Comment(4)
Hmm how does Unchecked.defaultof<'``Num<'M>``> * (LanguagePrimitives.GenericOne : 'Num) prevent "FS0030: Value restriction" error? Also how did you come up with x: '``Num<'M>`` ? Surprised to see the compiler accepts itCeliaceliac
I don't see why there should be a value restriction, the goal of that line is to make the compiler infer a type called 'Num without caring about the result. Regarding the other type variable, the F# compiler accepts whatever is written between double quotes, but it interprets it as a string the represents a single identifier without giving it a special meaning, so the <'M> inside it is not a type variable application, it could be anything without any specific meaning for the compiler.Homocyclic
Thanks. I see, so renaming '``Num<'M>`` to 'T doesn't change the bahavior of your function. And SRTP tells the compiler to find a 'Num such that static member (*): 'T -> 'Num -> 'Any is valid... something like that? That rocks! There seems to be a bit of gap between what I learned as HM type inference/unification and what's powering an industrial-strength compiler...Celiaceliac
Yes, type equations are powered simply by overload, the compiler uses the constraint solver in order to do overload resolution, once an overload is select, type inference continues with the types unified with the selected overload.Homocyclic
S
1
[<Measure>]type m
let f (arr : float[]) : float = 0.0
let arr = [|1.0<m>|]
f (unbox (box arr))
Shady answered 9/7, 2012 at 22:28 Comment(0)
S
1
let demeasure (arr: float<m>[])  = arr |> Array.map (fun i -> float i)
Singlephase answered 24/1, 2013 at 15:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.