elm-units

Simple, safe and convenient unit types and conversions for Elm

BSD-3-CLAUSE License

Stars
84
Committers
11

Bot releases are hidden (Show)

elm-units - 2.10.0 Latest Release

Published by ianmackenzie over 1 year ago

This release brings a new Torque module (thanks @gampleman!) plus one new function: Quantity.sign, for getting the sign of a quantity.

elm-units - 2.9.0

Published by ianmackenzie over 3 years ago

This release brings a number of useful new functions to the Quantity module.

Comparisons against zero

It's fairly common to check if a value is less than or greater than zero, for example to check if something is moving up or down:

if verticalSpeed |> Quantity.lessThan Quantity.zero then
    -- Falling down

else
    -- Moving up (or stationary)

A few new convenient shorthands have been added for these cases:

Quantity.lessThanZero : Quantity number units -> Bool
Quantity.greaterThanZero : Quantity number units -> Bool
Quantity.lessThanOrEqualToZero : Quantity number units -> Bool
Quantity.greaterThanOrEqualToZero : Quantity number units -> Bool

Non-infix versions of arithmetic operators

The existing arithmetic operators in elm-units are generally intended to be used in 'pipeline' or 'infix' form, for example

rotation =
    endAngle |> Quantity.minus startAngle

area =
    length |> Quantity.times width

speed =
    distance |> Quantity.per time

Sometimes, however, it is cleaner or more understandable to write these without a pipe, and there are now new functions that allow this style:

rotation =
    Quantity.difference endAngle startAngle

area =
    Quantity.product length width

speed =
    Quantity.rate distance time

Multiplying rates of change

Sometimes you have two rates of change and you want to combine them to get a new rate of change. For example, if you know distance per unit time (speed), and mass of CO₂ emitted per unit distance, then you can get mass of CO₂ emitted per unit time using the new Quantity.rateProduct:

speed =
    Length.kilometers 100 |> Quantity.per Duration.hour

emissionsPerKilometer =
    Mass.grams 200 |> Quantity.per Length.kilometer

Quantity.rateProduct speed emissionsPerKilometer
--> Mass.grams 5.555 |> Quantity.per Duration.second

Arithmetic on unitless quantities

When doing arithmetic on unitless quantities, specialized functions are needed to avoid the result having weird units like Product Unitless Meters. elm-units already has a few functions (such as timesUnitless and overUnitless) for these cases, but this release adds several more:

Quantity.reciprocal : Quantity Float Unitless -> Quantity Float Unitless
Quantity.squaredUnitless : Quantity number Unitless -> Quantity number Unitless
Quantity.sqrtUnitless : Quantity Float Unitless -> Quantity Float Unitless
Quantity.cubedUnitless : Quantity number Unitless -> Quantity number Unitless
Quantity.cbrtUnitless : Quantity Float Unitless -> Quantity Float Unitless
elm-units - 2.8.0

Published by ianmackenzie over 3 years ago

This release brings a couple of small improvements - first of all, the Volume module now has cubicCentimeters as an alias for milliliters thanks to @g-belmonte in #54:

Volume.cubicCentimeter : Volume
Volume.cubicCentimeters : Float -> Volume
Volume.inCubicCentimeters : Volume -> Float

Second, the Quantity module now has timesUnitless and overUnitless functions to smooth out some slightly annoying type-related wrinkles when multiplying and dividing by unitless quantities:

Quantity.timesUnitless : Quantity number Unitless -> Quantity number units -> Quantity number units
Quantity.overUnitless : Quantity Float Unitless -> Quantity Float units -> Quantity Float units

(For example, using timesUnitless lets you get a result with units type units instead of the Product Unitless units that you would get if you used the existing times.)

elm-units - 2.7.0

Published by ianmackenzie about 4 years ago

This release brings a few small new functions:

Angle.normalize : Angle -> Angle 
Quantity.unsafe : number -> Quantity number units
Quantity.unwrap : Quantity number units -> number

Angle.normalize is used to convert an arbitrary angle into the equivalent angle in the range -180 to +180 degrees; for example 330 degrees normalizes to -30 degrees. Note that you may need to be careful with roundoff error for angles near 180 degrees or -180 degrees; for example 180.0001 degrees will normalize to -179.9999 degrees which may not be what you expect.

Quantity.unsafe and Quantity.unwrap are equivalent to directly constructing/destructuring Quantity values and should generally be avoided if possible, but are useful in some low-level situations that may come up in packages that use elm-units.

elm-units - 2.6.0

Published by ianmackenzie over 4 years ago

This release brings a few new functions to the Pixels module:

Pixels.int : Int -> Quantity Int Pixels
Pixels.float : Float -> Quantity Float Pixels

Pixels.toInt : Quantity Int Pixels -> Int
Pixels.toFloat : Quantity Float Pixels -> Float

I find these a bit more readable/less awkward than the existing Pixels.pixels and Pixels.inPixels, but those two functions have the advantage of working with the generic number type instead of being specific to Int or Float - for example it is occasionally useful that a value like

screenWidth =
    Pixels.pixels 1920

can be passed to both functions that expect Quantity Int Pixels as well as ones that expect Quantity Float Pixels, without having to do any conversions such as Quantity.toFloatQuantity.

As a general rule, I suggest using Pixels.int/Pixels.float in most cases, and Pixels.pixels only if it makes the code shorter and cleaner.

elm-units - 2.5.1

Published by ianmackenzie over 4 years ago

This release fixes one small docs typo in the AngularSpeed module; thanks @objarni for pointing it out!

elm-units - 2.5.0

Published by ianmackenzie over 4 years ago

This release brings a few more features requested or contributed by the community. First of all, some additional functions for working with atomic-scale lengths, contributed by @ChrisWellsWood in #49:

Length.nanometers : Float -> Length
Length.inNanometers : Length -> Float

Length.angstroms : Float -> Length
Length.inAngstroms : Length -> Float

Length.nanometer : Length
Length.angstrom : Length

Next, a couple functions for using Duration values to offset Time.Posix values:

Duration.addTo : Time.Posix -> Duration -> Time.Posix
Duration.subtractFrom : Time.Posix -> Duration -> Time.Posix

(Note that these operations are lossy - a Time.Posix value is represented by an integer number of milliseconds, so it is only possible to offset by an integer numbers of milliseconds.)

Finally, some modulo/remainder functions to match Elm's built-in modBy and remainderBy functions, but also extended to work with Quantity Float units values (similar to how fractionalModBy from elm-community/basics-extra extends modBy to work with Floats):

Quantity.modBy : Quantity Int units -> Quantity Int units -> Quantity Int units
Quantity.remainderBy : Quantity Int units -> Quantity Int units -> Quantity Int units
Quantity.fractionalModBy : Quantity Float units -> Quantity Float units -> Quantity Float units
Quantity.fractionalRemainderBy : Quantity Float units -> Quantity Float units -> Quantity Float units
elm-units - 2.4.0

Published by ianmackenzie over 4 years ago

This release adds some CSS/typography units to the Length module:

Length.points : Float -> Length
Length.inPoints : Length -> Float

Length.picas : Float -> Length
Length.inPicas : Length -> Float

Length.cssPixels : Float -> Length
Length.inCssPixels : Length -> Float

Points and picas are standard typographical units equal to 1/72 and 1/6 of an inch respectively. Similarly, the CSS spec defines a pixel as nominally equal to 1/96 of an inch. Note the difference between Length.cssPixels 1 and the existing Pixels.pixels 1:

> Length.cssPixels 1
Quantity 0.0002645833333333333 : Quantity Float Meters

> Pixels.pixels 1
Quantity 1 : Quantity Float Pixels

That is, Length.cssPixels 1 is actually a physical measurement (the real-world size of one pixel on a 96 DPI monitor), while Pixels.pixels 1 is an abstract "one pixel" value.

Usually you will probably want to use Pixels.pixels, but Length.cssPixels may be useful if you are combining real-world and on-screen units. For example, using Length.cssPixels with the upcoming elm-3d-scene package will let you fairly naturally set up a 3D scene using pixel sizes (to get a specific on-screen size in pixels) while still being able to use proper physically-based lighting.

elm-units - 2.3.0

Published by ianmackenzie over 4 years ago

Version 2.3.0 of elm-units brings a variety of handy new features.

Quantity functions

There are now functions to get the maximum or minimum value in a List based on some derived Quantity:

Quantity.minimumBy : (a -> Quantity number units) -> List a -> Maybe a
Quantity.maximumBy : (a -> Quantity number units) -> List a -> Maybe a

Thanks @MartinSStewart for the suggestion! There is also now a Quantity.in_ function for doing conversions into units that aren't directly supported by elm-units:

Quantity.in_ : (Float -> Quantity Float units) -> Quantity Float units -> Float

Thanks @harrysarson for the idea! You might use it like this to get a speed in feet per minute:

Speed.metersPerSecond 5
    |> Quantity.in_ (Length.feet >> Quantity.per Duration.minute)
--> 984.252

Constants

The eagle-eyed reader may have noticed that Duration.minute in the above example is new. Partially to make the use of Quantity.in_ more convenient, but also because they're likely to be generally useful, this release defines a large number of unit constants in the Length, Duration, Angle, Mass, Area, Volume, Temperature and Pixels modules: Length.meter, Duration.minute, Volume.imperialGallon etc. This means you can write

Length.feet >> Quantity.per Duration.minute

instead of

Length.feet >> Quantity.per (Duration.minutes 1)

New Molarity module

Finally, thanks to @lenards in #44 for contributing a new Molarity module! Molarity represents concentration of a substance per unit volume and is useful in chemistry applications. Along with the new Molarity module, direct support for centimoles and decimoles were added to the existing SubstanceAmount module.

elm-units - 2.2.0

Published by ianmackenzie about 5 years ago

elm-units 2.2.0 brings three main changes: new modules for working with photometric units, support for working with angles in degrees/minutes/seconds form, and a couple new convenience functions for Quantity values.

Photometric units

This release brings new modules for dealing with different kinds of photometric quantities: SolidAngle, LuminousFlux, LuminousIntensity, Illuminance and Luminance. These kinds of quantities can be very confusing to think about - I've tried to describe them briefly in each module's documentation, but if you're new to the field then you'll probably have to do some reading of your own!

Angles in degrees, minutes and seconds

In some situations, such as when dealing with geographical data, it is common to represent angles as a number of degrees, minutes (1/60th of a degree) and seconds (1/60th of a minute). This release brings a handful of functions (and a new Angle.Sign type) to work with these kinds of values:

Angle.minutes : Float -> Angle
Angle.inMinutes : Angle -> Float
Angle.seconds : Float -> Angle
Angle.inSeconds : Angle -> Float
Angle.fromDms : { sign : Angle.Sign, degrees : Int, minutes : Int, seconds : Float } -> Angle
Angle.toDms : Angle -> { sign : Angle.Sign, degrees : Int, minutes : Int, seconds : Float }

Quantity convenience functions

A couple tiny convenience functions have been added to the Quantity module: twice, as a convenient shorthand for multiplyBy 2, and half as shorthand for multiplyBy 0.5.

elm-units - 2.1.0

Published by ianmackenzie over 5 years ago

This release of elm-units comes with just one user-visible change, the addition of a range function for generating evenly-spaced values:

Quantity.range
    { start = Length.meters 2
    , end = Length.meters 3
    , steps = 5
    }
--> [ Length.centimeters 200
--> , Length.centimeters 220
--> , Length.centimeters 240
--> , Length.centimeters 260
--> , Length.centimeters 280
--> , Length.centimeters 300
--> ]

Not visible is a ton of work that went into refactoring elm-units internals to collect all conversion factors into one place. We now have a single nicely-readable Constants.elm file with all the various conversion factors, for easy reuse and auditability. Thanks to @katjam for all her work on #23!

elm-units - 2.0.2

Published by ianmackenzie over 5 years ago

Fix to API docs link in README (thanks @katjam!)

elm-units - 2.0.1

Published by ianmackenzie almost 6 years ago

Add release notes link to README

elm-units - 2.0

Published by ianmackenzie almost 6 years ago

elm-units 2.0 is out! This release adds several new quantity types, improves support for multiplication of different types of quantities, and adds a few more useful functions to the Quantity module.

Updating code

To update code using elm-units 1.0 to 2.0, it should be sufficient to replace

  • Quantity.times with Quantity.for
  • Quantity.product with the new Quantity.times
  • Quantity.scaleBy with Quantity.multiplyBy

For example:

----- 1.0 -----

length =
    speed |> Quantity.times duration

area =
    Quantity.product length width

halfLength =
    Quantity.scaleBy 0.5 length

----- 2.0 -----

length =
    speed |> Quantity.for duration

area =
   length |> Quantity.times width

halfLength =
    Quantity.multiplyBy 0.5 length

See Improved product support below for details.

New quantity types

This release adds support for several new quantity types:

  • Volume (cubic meters) - thanks @katjam!
  • Density (kilograms per cubic meter) - thanks @katjam!
  • AngularSpeed (radians per second) - thanks @katjam!
  • AngularAcceleration (radians per second squared) - thanks @katjam!
  • Capacitance (farads) - thanks @ukarim!
  • Inductance (henries) - thanks @ukarim!
  • SubstanceAmount (moles) - thanks @ukarim!

Improved product support

Support for products of two quantities is now generalized and improved. Previously it was possible to square a quantity using Quantity.squared or multiply two quantities with the same units using Quantity.product (both of which gave you a result in Squared units), but there was no way to multiply two quantities with different units. This is now supported - for example, it is now possible to multiply an Area by a Length to get a Volume, or a Mass by an Acceleration to get a Force. It is also now possible to divide these products, for example divide a Force by a Mass to get an Acceleration.

This has led to a couple of breaking changes. First of all, the existing Quantity.times (used when working with rates of change) has been renamed to Quantity.for, and Quantity.times is now used for multiplying quantities together, replacing the old Quantity.product. For example:

area =
    width |> Quantity.times length

volume =
    area |> Quantity.times depth

force =
    mass |> Quantity.times acceleration

In addition, for consistency with divideBy, scaleBy has been renamed to multiplyBy. There are now three 'families' of multiplication/division functions for use in different contexts:

  • multiplyBy and divideBy are used to multiply (scale) or divide a Quantity by a plain Int or Float
  • times, over and over_ are used to work with quantities that are products of other quantities, like Area or Volume
  • per, at, at_ and for are used to work with rates of change, like Speed or or Current

See Multiplication and division in the README for more details.

The new products support is made possible by a new Product units1 units2 units type. This has led to the redefinition of some existing units types:

  • Squared units has been redefined as Product units units
  • Cubed units has been redefined as Product (Product units units) units
  • Joules has been redefined as Product Newtons Meters
  • Newtons has been changed from Rate Joules Meters to Product Kilograms MetersPerSecondSquared

New Quantity functions

A few new functions have been added to the Quantity module:

  • Quantity.lessThanOrEqualTo and Quantity.greaterThanOrEqualTo to go with the existing Quantity.lessThan and Quantity.greaterThan
  • Quantity.interpolateFrom to interpolate from one value to another
  • Quantity.midpoint to find the midpoint between two quantities
  • Quantity.sortBy to sort an arbitrary list of values by a derived quantity
elm-units - 1.0

Published by ianmackenzie about 6 years ago

elm-units 1.0 has been released! Check out the README for a fairly comprehensive introduction to the package, and don't be afraid to reach out if you have questions/comments/suggestions.

Big thanks to all those who helped with initial development of the package:

  • @JoelQ and @adeschamps for in-depth and insightful discussions on Slack
  • Everyone at the Elm NYC Meetup for providing comments on an early version of the package
  • Everyone in the #api-design channel on the Elm Slack for their pre-release feedback
  • @tiagorlampert and @mdevlamynck for making PRs to an Elm package that hadn't even been published yet!

(Sincere apologies to anyone I've missed.)