ianmackenzie / elm-units

Simple, safe and convenient unit types and conversions for Elm
https://package.elm-lang.org/packages/ianmackenzie/elm-units/latest/
BSD 3-Clause "New" or "Revised" License
84 stars 14 forks source link

Add support for non-negative units #60

Open DavidDTA opened 2 years ago

DavidDTA commented 2 years ago

The Quantity API allows for the wrapped value to be any numeric value. In some cases, units that are less than zero are not possible, and it would be nice to make impossible states impossible in those cases.

One way to accomplish this would be to introduce a new type (e.g. AbsoluteQuantity) which enforces that its value is always non-negative via its API.

My specific use case involves measuring periods of time, and

type alias TimeBlock = { start: Time.Posix, duration = Duration.Duration }

allows for impossible states when the duration is negative, but

type alias TimeBlock = { start: Time.Posix, duration = <non-negative duration type here> }

does not.

ianmackenzie commented 2 years ago

I think a new type like NonNegativeQuantity would be tricky, since then you'd presumably need NonNegativeDuration, NonNegativeLength etc. types/modules, with a bunch of duplicate logic to create a new NonNegativeDuration from a non-negative value in seconds, minutes, hours etc. - it would basically be a full separate copy of the elm-units API.

One possibility might be to (ab)use the first type parameter of Quantity to use an underlying non-negative numeric type (e.g. a hypothetical NonNegativeFloat type, published as an independent package). By itself that wouldn't be super useful since you wouldn't be able to use any of the functions in (e.g.) the Duration module, but if we added something like

Quantity.map : (a -> b) -> Quantity a units -> Quantity b units

then you could do something like Quantity.map NonNegativeFloat.toFloat myNonNegativeQuantity to get a 'normal' quantity that you could do math with. (I'd be open to adding map, map2 etc. functions - they're a little unsafe since they would provide a pretty easy way to subvert units safety, but I can see them being pretty useful in some cases.)