serokell / o-clock

:hourglass: Type-safe time units in Haskell
Mozilla Public License 2.0
49 stars 6 forks source link

Order of type arguments #130

Closed dcastro closed 2 years ago

dcastro commented 2 years ago

o-clock has a few functions for converting between Time units, or from Time unit to something else.

In general, we use ExplicitForAll and order the type variables so that the target type comes first and the source type comes last:

toUnit :: forall (unitTo :: Rat) (unitFrom :: Rat). KnownDivRat unitFrom unitTo => Time unitFrom -> Time unitTo

toNum :: forall (unitTo :: Rat) n (unit :: Rat). (KnownDivRat unit unitTo, Num n) => Time unit -> n

We do this under the assumption that the type of the argument is usually explicit or can be inferred by GHC, so the user will almost always be more interested in specifying the target type using TypeApplications (and omit the source type):

-- We can omit the source type @Hour
λ> toUnit @Minute $ hour 3
180m

-- We can omit the source type @Hour
λ> toNum @Minute @Int $ hour 3
180

However, floorRat seems to be the odd one out:

floorRat :: forall (unit :: Rat) b. Integral b => Time unit -> b
λ> floorRat @_ @Int $ hour 3
3

For consistency, we should reorder the type variables of floorRat.