Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# generic units in parameters defined in terms of each other

I am having trouble with F# Units of Measure when defining an operator that has a parameter with a generic unit of measure defined in terms of the generic unit of measure from another parameter. For example:

type Quotient<[<Measure>]'b> =
| Divisible of int64<'b>
| Remaindered of int64<'b> * int64<'b>

let (|/) (x: int64<'a>) (y: int64<'a/'b>) =
    let q = x / y
    if q * y = x then Divisible q else Remaindered (q, x - (q * y))  

Here, y is defined in <'a/'b>, where <'a> is the unit of x. I am expecting the type of (|/) to be int64<'a> -> int64<'a/'b> -> Quotient<'b>, however the compiler is telling me the type is x:int64<'b> -> y:int64 -> Quotient<'b>.

I want to use this for type conversions where decimal numbers are not possible. My goal was to create operators for working with Quotients instead of putting the logic to compute the remainder in every type conversion. Is it possible to achieve this goal, or should I go about my type conversions a different way?

like image 711
Aaron M. Eshbach Avatar asked Mar 11 '16 22:03

Aaron M. Eshbach


1 Answers

Interesting question. If you take out the 'a/'b and replace it with 'b, you'll see that the compiler suddenly gives you a warning on the - operator.

It's telling you that the units on the left and right of the subtraction have to be the same so it has constrained 'b to be of measure 1. Why?

x has units of 'a

q has units of 'b

This tells you that you actually need two measure parameters for your quotient.

type Quotient<[<Measure>]'a, [<Measure>]'b> =
    |Divisible of int64<'a>
    |Remaindered of int64<'a> * int64<'b>

This make sense because any remainder would be in the original units.

let (|/) (x: int64<'a>) (y: int64<'a/'b>) : Quotient<'b,'a>  =
    let q = x / y
    if q * y = x then Divisible q else Remaindered (q, x - q * y)
like image 54
TheInnerLight Avatar answered Oct 02 '22 17:10

TheInnerLight