Coder Social home page Coder Social logo

units's People

Contributors

dougburke avatar gambogi avatar gittywithexcitement avatar goldfirere avatar hesiod avatar jcristovao avatar leftaroundabout avatar nushio3 avatar ocharles avatar rimmington avatar ryanglscott avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

units's Issues

evalType fails for Volume (and other such types)

Since 806a27d (issue #22), the evalType TH function is available to evaluate types as far as possible. This works well for, e.g., Mass and Length. However, the following instance fails:

instance Show $(evalType [t| Volume |]) where

Giving the following error:

    evalType [t| Volume |]
  ======>
    Qu ((@*) ((GHC.Types.:) (F Data.Metrology.SI.Dims.Length (S Zero)) GHC.Types.[]) (S (S (S Zero)))) DefaultLCSU Double

src/NutriDB/AbsSyn.hs:68:10:
    Illegal type synonym family application in instance:
      Qu
        ('['F Data.Metrology.SI.Dims.Length ('S 'Zero)]
         @* 'S ('S ('S 'Zero)))
        'DefaultLCSU
        Double
    In the instance declaration for
      ‘Show (Qu ((@*) ((:) (F Data.Metrology.SI.Dims.Length (S Zero)) []) (S (S (S Zero)))) DefaultLCSU Double)’
Failed, modules loaded: NutriDB.DefaultValue.

In fact, all types defined using the :/ combinator (and possibly others, such as :^) fail with the same error. While these types are indeed more complex than Mass and Length, they at first glance don't appear to be very polymorphic, suggesting that it may be possible to use evalType with types such as Volume as well.

adding a show instance results in type-inference problems (may be an IHaskell issue)

{this is not a time-critical issue for me}

This is done in an IHaskell notebook using ghc 7.8.4, with units 2.21 and units-defs 2.0. Am I doing something wring here with the Show instance?

:set -XTypeFamilies

import Data.Metrology
import Data.Metrology.SI
import Data.Metrology.Show

-- From http://en.wikipedia.org/wiki/Astronomical_unit 
data AstronomicalUnit = AstronomicalUnit

instance Unit AstronomicalUnit where
  type BaseUnit AstronomicalUnit = Meter
  conversionRatio _ = 149597870700

d = 9.2e-27 % (Kilo :@ Gram :/ (Meter :^ sThree))

I can then convert this into a different set of units (picked to give a reasonably-sized number rather than that it is any-way useful!):

d # (Kilo :@ Ton :/ (AstronomicalUnit :^ sThree))

The output of this conversion is

30.800946577458888

Now if I add in a Show instance:

instance Show AstronomicalUnit where
  show _ = "au"

Re-evaluating the conversion results in an error:

d # (Kilo :@ Ton :/ (AstronomicalUnit :^ sThree))
Could not deduce (Unit AstronomicalUnit) arising from a use of ‘#’
from the context (Fractional n) bound by the inferred type of it :: Fractional n => n at :1:1-49
In the expression: d # (Kilo :@ Ton :/ (AstronomicalUnit :^ sThree))
In an equation for ‘it’: it = d # (Kilo :@ Ton :/ (AstronomicalUnit :^ sThree))

export internal types to keep error messages shorter

See how unreadable type errors are now:

Couldn't match type ‛units-1.1:Data.Dimensions.DimSpec.Reorder
                       d20
                       '['units-1.1:Data.Dimensions.DimSpec.D Gram ('P 'Zero),
                         'units-1.1:Data.Dimensions.DimSpec.D Meter 'Zero,
                         'units-1.1:Data.Dimensions.DimSpec.D Second One]
                     units-1.1:Data.Dimensions.DimSpec.@@- '['units-1.1:Data.Dimensions.DimSpec.D
                                                               Gram ('P 'Zero),
                                                             'units-1.1:Data.Dimensions.DimSpec.D
                                                               Meter 'Zero,
                                                             'units-1.1:Data.Dimensions.DimSpec.D
                                                               Second One]’
              with ‛'['units-1.1:Data.Dimensions.DimSpec.D Gram One,
                      'units-1.1:Data.Dimensions.DimSpec.D Second One]’
The type variable ‛d20’ is ambiguous

Develop a monomorphic interface

It would be nice for users to be able to define just units -- not dimensions -- and get to work. This interface would be exported from Data.Metrology.Mono. My guess is that it will require Template Haskell.

Cannot build on GHC 9

If I change units.cabal to depend on singletons-th I get a bit further, but then I get:

Data/Metrology/Z.hs:81:2: error: Cannot find type annotation for ==
   |
81 | $(singletons [d| data Z = Zero | S Z | P Z deriving Eq |])
   |  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Data/Metrology/Z.hs:81:2: error: Q monad failure
   |
81 | $(singletons [d| data Z = Zero | S Z | P Z deriving Eq |])
   |  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

At this point I'm not sure what to do

Quantity vector, or vector of quantities?

On writing the test for #31: (please look at comments in https://github.com/goldfirere/units/blob/309236af6dcc6aae4da1bb4b2c7bab91534b6614/Tests/Vector.hs) ,

I noticed that the current design of Data.Metrology.Vector requires Fractional instance for V n where V is the vector type constructor. Particularly, in this case Fractional (Rational, Rational) . I think such instances are not generally available.

From this viewpoint, it seems more natural to define and operate over types of the form V (Qu d l n) , rather than Qu d l (V n) .

This problem is important to me. Because I'm going to do physical simulations using units , I inevitably deal with array of quantities. I've been thinking about this for some time. But just thinking. Thank you for bringing up this issue as a concrete problem with codes!

Document why `Data.Metrology.Linear` wants `Qu` on the outside

Hi, bit of an odd "issue", but please bear with me!

We've just started using units in a computer vision application, and almost all the measurements we have are two-dimensional vectors. Looking at https://github.com/goldfirere/units/blob/master/Tests/Compile/Simulator.hs, it's clear that the intention is to represent entire vectors an quantities, but it felt more natural for us (when using linear) to have Qu under the vector itself. That is...

velocity :: V2 Length

Is there a fundamental reason why this is a bad idea? It seems that with this approach, Data.Metrology.Linear isn't necessary at all (except for maybe providing a few orphan instances), as Linear is already sufficiently polymorphic to support units.

Consider depending on vector-spaces

The vector-spaces package defines several classes that may be useful to us, especially if we want to allow users to assign a dimension/unit to a vector, instead of a scalar. This might be low priority right now, but I wanted to document the idea.

Compile error on ghc-8.2.2

Using stack to install I get the following error:

--  While building custom Setup.hs for package units-2.4 using:
      /Users/xavier/.stack/setup-exe-cache/x86_64-osx/Cabal-simple_mPHDZzAJ_2.0.1.0_ghc-8.2.2 --builddir=.stack-work/dist/x86_64-osx/Cabal-2.0.1.0 build --ghc-options " -ddump-hi -ddump-to-file -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1
    Logs have been written to: /Users/xavier/Personal/haskell-sandbox/.stack-work/logs/units-2.4.log

    Configuring units-2.4...
    Preprocessing library for units-2.4..
    Building library for units-2.4..
    [ 1 of 19] Compiling Data.Metrology.Set ( Data/Metrology/Set.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/Set.o )
    [ 2 of 19] Compiling Data.Metrology.Z ( Data/Metrology/Z.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/Z.o )
    [ 3 of 19] Compiling Data.Metrology.Factor ( Data/Metrology/Factor.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/Factor.o )
    [ 4 of 19] Compiling Data.Metrology.LCSU ( Data/Metrology/LCSU.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/LCSU.o )
    [ 5 of 19] Compiling Data.Metrology.Dimensions ( Data/Metrology/Dimensions.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/Dimensions.o )
    [ 6 of 19] Compiling Data.Metrology.Units ( Data/Metrology/Units.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/Units.o )
    [ 7 of 19] Compiling Data.Metrology.Qu ( Data/Metrology/Qu.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/Qu.o )
    [ 8 of 19] Compiling Data.Metrology.Unsafe ( Data/Metrology/Unsafe.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/Unsafe.o )
    [ 9 of 19] Compiling Data.Metrology.Show ( Data/Metrology/Show.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/Show.o )
    [10 of 19] Compiling Data.Metrology.Combinators ( Data/Metrology/Combinators.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/Combinators.o )
    [11 of 19] Compiling Data.Metrology.Validity ( Data/Metrology/Validity.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/Validity.o )
    [12 of 19] Compiling Data.Metrology.Linear ( Data/Metrology/Linear.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/Linear.o )
    [13 of 19] Compiling Data.Metrology.Internal ( Data/Metrology/Internal.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/Internal.o )
    [14 of 19] Compiling Data.Metrology.Vector ( Data/Metrology/Vector.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/Vector.o )
    [15 of 19] Compiling Data.Metrology.Poly ( Data/Metrology/Poly.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/Poly.o )
    [16 of 19] Compiling Data.Metrology.TH ( Data/Metrology/TH.hs, .stack-work/dist/x86_64-osx/Cabal-2.0.1.0/build/Data/Metrology/TH.o )
    
    /private/var/folders/mx/91rymfz14gl9r0ffxhf2j9d8000152/T/stack36007/units-2.4/Data/Metrology/TH.hs:222:69: error:
        • Couldn't match type ‘Type’ with ‘DerivClause’
          Expected type: [DerivClause]
            Actual type: [Type]
        • In the sixth argument of ‘DataD’, namely ‘(map ConT derivs)’
          In the expression:
            DataD ct name tvbs Nothing cons (map ConT derivs)
          In an equation for ‘mkDataD’:
              mkDataD ct name tvbs cons derivs
                = DataD ct name tvbs Nothing cons (map ConT derivs)
        |
    222 | mkDataD ct name tvbs cons derivs = DataD ct name tvbs Nothing cons (map ConT derivs)
        |    

Sorry I'm too new to haskell to be much help in fixing :(

Rejigger Num instance

It might be better to have

deriving instance (d ~ '[], Num d) => Num (Qu d l n)

or something similar to get better inference.

Fix definition of `@~`

I want this to work:

ratio :: (d1 @~ d2) => Qu d1 l n -> Qu d2 l n -> n
ratio x y = (x |/| y) # Number

But it doesn't, because d1 @~ d2 does not imply that Normalize (d1 @- d2) ~ '[]. Perhaps a different definition of @~ would work.

Does it make sense to have a polymorphic "NumberOf" dimension?

Apologies for the somewhat sloppy issue title, it's hard to summarise this in a single sentence!

I'm using units to build a pricing model for some work we do at CircuitHub. Namely, I'm interested in a pricing model grounded by a sensible real-world interpretation. units works nicely for this - I introduced a new Cost dimension (with $ unit), and now I can say things like MkQu_DLN (Cost :/ Area) - nice!

However, a lot of our costs are actually per some specific unit. For example, parts prices expressed as unit prices. Currently, these are MkQu_DLN Cost, but they are really cost per something - and here my modeling is a bit stuck.

I could introduce a new PartQuantity dimension, but this idea of a count seems to keep cropping up. It seems natural to me to have a

data NumberOf x

dimension, such that I can have things like partUnitCost :: MkQu_DLN (Cost :/ NumberOf Part).

I'm curious if this really fits in with the spirit of units though. In particular, it seems like a strange dimension, as it doesn't really have any units, other than an exact count of the things in question. On the other hand, it does a very good job of making sure I scale a per-unit part cost by the actual number of parts I need to order!

What do the others think?

support LaTeX expressions of units

See how the units are rendered in The Solar physics sample article .

The Solar luminosity is 3.839e30 (kg * m^2)/s^3, or 3.839e30 W.

We'd like to utilize the LaTeX's ability and represent units more beautifully, using superscripts and special unit symbols (e.g. \AA for angstrom and \mu for micro.)

I think a way to do this is to define Render instances for specific unit types in units-defs and for unit combinators.in units . There can be other ways with other benefits. For example we may not want units to depend on HaTeX package. We can permit orphan instances. I'd like to listen for better ways.

Export monomorphic combinators

A few minutes ago, I wanted to know how many yards there are in a mile. So, I said this:

(1 % Mile) # Yard

In response, I got complaints about an ambiguous LCSU. That makes enough sense, but it sure is exasperating for a user just taking this for a quick spin.

I propose new operators %% and ## that are monomorphic in their LCSU (requiring a DefaultLCSU) to make the above easier. We would export these from Data.Metrology.Mono and could encourage first-time users to try the mono functions first.

See also issue goldfirere/units-defs#2, which discusses related changes to the structure of the SI modules to support monomorphic programming.

Applicative/Functor instances for Qu

Maybe this is a terrible idea; I'd appreciate feedback. I think I want instances of all the Functor-related classes for Qu d l. Some uses would be semantically strange but still useful; for instance, Qu Length l (Int -> Float) is a funny-looking type but I guess it's a function that, given a length as an Int, returns a (possibly different) length as a Float. Obviously most of the library can't operate on such a type, but you'd use it with Applicative's <*> as an intermediate value on the way to something that the library can operate on.

My immediate use cases are that:

  1. I want to read sensor values from hardware as, say, Int16; tag them with a unit describing how to convert from hardware ADC counts to an SI unit, but not change their representation yet; and only later when I actually need to compute on them, fmap fromIntegral to convert them to Float and then maybe pick a new LCSU.
  2. I'm using kmett's linear and ad packages, which involve structuring my matrices and systems of equations as data types which are instances of Functor and assorted other classes. I want to tag dimensionality on all the elements of each matrix, but I think writing my Functor etc. instances will require the corresponding classes for Qu. I could write them directly in terms of Data.Metrology.Unsafe but that would be messy.

Cannot create point quantities because Point is not an instance of VectorSpace

The (%) needs its operand on the left side to be an instance of VectorSpace because it scales it to the canonical unit. But point quantities cannot be scaled (I don't know enough geometry to say if that makes sense).

I hope I haven't forgot any parentheses this time! 😄

Example:

λ> import Data.Metrology.Vector
λ> let p = Point (0::Double, 1::Double)
λ> p
Point (0.0,1.0)
λ> :i p
p :: Point (Double, Double)     -- Defined at <interactive>:3:5
λ> import Data.Metrology.SI.Poly
λ> let p' = p % Meter

<interactive>:6:12:
    Could not deduce (Data.VectorSpace.VectorSpace
                        (Point (Double, Double)))
      arising from a use of ‘%’
    from the context (Elem
                        Meter
                        '[CanonicalUnit'
                            (BaseUnit (Lookup Data.Dimensions.SI.Length lcsu))
                            (Lookup Data.Dimensions.SI.Length lcsu)],
                      Elem
                        (CanonicalUnit'
                           (BaseUnit (Lookup Data.Dimensions.SI.Length lcsu))
                           (Lookup Data.Dimensions.SI.Length lcsu))
                        '[Meter],
                      Unit (Lookup Data.Dimensions.SI.Length lcsu))
      bound by the inferred type of
               p' :: (Elem
                        Meter
                        '[CanonicalUnit'
                            (BaseUnit (Lookup Data.Dimensions.SI.Length lcsu))
                            (Lookup Data.Dimensions.SI.Length lcsu)],
                      Elem
                        (CanonicalUnit'
                           (BaseUnit (Lookup Data.Dimensions.SI.Length lcsu))
                           (Lookup Data.Dimensions.SI.Length lcsu))
                        '[Meter],
                      Unit (Lookup Data.Dimensions.SI.Length lcsu)) =>
                     Qu
                       '['F Data.Dimensions.SI.Length One] lcsu (Point (Double, Double))
      at <interactive>:8:5-18
    In the expression: p % Meter
    In an equation for p'’: p' = p % Meter

Fix Imperial units

There is some work to do to make imperial units releasable:

  • How inclusive should we be? Are these standardized anywhere?
  • How to differentiate between US measures and UK measures, where they differ?
  • How to convert between grams and pounds? They don't measure the same thing!

Spin-out parser as a separate package

The parser for unit expressions in Data.Metrology.Parser.Internal is very nice, and I think it could be useful independently from units. (Full disclosure: I'm writing my own units of measure library, based on experiments with GHC typechecker plugins, and I'd much rather steal your parser than write my own!) Would you be receptive to a pull request if I create a tiny package (perhaps units-parser) and adapt units to work with it instead? My intention would be that all the TH-related functionality remain in units:Data.Metrology.Parser and only parseUnit and its dependencies move.

At the same time, I'd like to introduce a small generalization: rather than requiring a finite map from strings to units, we could take type UnitTable u = String -> Maybe u. This would allow my library to represent units as strings, and not determine the list of units in advance of invoking the parser (but obviously there would be no ambiguity check in such a case). The existing interface could be supported except that SymbolTable would lose its Show instance. Does this sound reasonable?

More general Eq and Ord instances

Currently Eq and Ord instances are only defined for dimensionless quantities:

deriving instance Eq n => Eq (Qu '[] l n)
deriving instance Ord n => Ord (Qu '[] l n)

I'm wondering why this can't be changed to quantities of any dimension:

deriving instance Eq n => Eq (Qu d l n)
deriving instance Ord n => Ord (Qu d l n)

These operators would still be less general than |==|, |<|, etc., because they don't do normalization with @~. But they'd be quite useful nevertheless, when using other functions that expect an Eq or Ord instance.

As far as I can tell this should be perfectly safe since the dimensions of the two compared quantities will be exactly the same.

Cannot make instances that mention `Qu` types

Say we want

instance ToJSON (Carbs Volume) where ...
instance ToJSON (Carbs Mass) where ...

We're stuck, because Volume and Mass expand to types that mention type families (specifically, DimFactorsOf). Yet, the code above is quite reasonable. This is directly related to GHC#8828, which asks, essentially, for code like the above to work. But, I've decided (and SPJ agrees) that GHC#8828 is a bad idea, for other reasons.

What to do? Of course, wrapping in a newtype would work. Are there other ways? A few minutes' thought says no.

(Interesting, but ultimately failed idea: It seems straightforward(-ish) to write deepseq's force function at the type level, which would evaluate all type family applications in a type. The problem is that there's no way to get the evaluation started. Even if we had type Volume = Force (MkQu...), there's nothing forcing the RHS of the type synonym. I can't come up with a way around this. Any GHC feature request that comes to mind seems to be a stand-in for proper type pattern synonyms, as requested in the revised GHC#8828.)

Leaving this open as a ticket to either come up with a solution or to document a workaround.

Make `allUnits` work.

Right now,

import Data.Units.SI
import Data.Units.US

do units <- allUnits
   makeQuasiQuoter "u" [] units

fails with a non-letter somewhere. There are multiple problems.

  1. Even if I restrict the imports, Template Haskell finds everything that's exported from any module, regardless of whether it's actually in scope. This may not be fixable.
  2. I'm pretty sure it's Ohms or Angstroms that are causing the trouble. But maybe not, because both symbols respond True to isLetter. In any case, it's not working.

I have no idea if the problem is in this package, in units-parser or in units-defs.

Handling temperature units

It looks to me like the units package doesn't currently support converting between units that have different zero-points, such as between degrees Kelvin, Celsius, and Fahrenheit. How could that work?

Scalar product: shall we normalize the dimension

With respect to the following update:
20100a6#diff-55b7a1b2fff6092d774c2e61be91ca57R236

Should scalar product normalize the dimension of quantities?

-- | Multiply a quantity by a scalar from the left
(*|) :: Num n => n -> Qu b l n -> Qu (Normalize b) l n
a *| (Qu b) = Qu (a * b)

The type signature used to be: (*|) :: Num n => n -> Qu b l n -> Qu b l n .

First of all, let me apologize my carelessness if the change was necessary to the updates recently made.

If I have choice, I'd prefer the older type signature that doesn't normalize the type.

I used the fact that the scalar product preserve the quantity type quite a lot in my research. For example, the following code makes some linear combination of function according to air composition:

airMix :: (ChemicalSpecies -> Qu d l Double) -> Qu d l Double
airMix func = 0.78 *| func N2 |+| 0.21 *| func O2 |+| 0.01 *| func Ar

Well, I was able to update the physics code by adding type constraint such as d ~ Normalize d . Then I need the new constraint everywhere I use airMix . In some sense, it can be good convention to encourage keep dimensions normalized.

In addition, the change introduced type errors where I use specific units such as radiance and spectral flux density. I assume the source of error is one of the power index of the dimensions cancelling out and going to zero. I'm trying to create a minimum working example. (Minimum not-working example, to be more precise.)

Anyway, my intuition is that scalar product doesn't change the direction of vector; 2 *| x is equivalent to x |+| x and qSum [x, x]. If the latter two does not normalize the dimension, my thinking is that the former don't, too.

Making Quantities from UnitExp

Firstly, many thanks for making this library available!

I'm having a bit of a conceptual issue/question that I haven't been able to resolve. I've managed to use this module quite successfully where I have all my quantities/units/dimensions and combinations thereof specified at compile time.

I am now trying to put together a little demonstration application which would accept Unit strings at runtime from a user and, provided the strings are parsed succesfully, perform conversions between them.

On a successful parse of an input string I have some data UnitExp pre unit. But I am not sure how to proceed from there. For instance a test function to try and make a quantity (say I have parsed "m/s" and lifted UnitExp out of the Either monad):

liftUnitExp :: (Show unit) => (UnitExp pre unit) -> Double -> IO ()  --Qu dim lcsu n
liftUnitExp (UnitExp pre unit) x = print (x % unit) 

Gives me a compilation error:

    • Could not deduce (UnitFactor
                          (LookupList (DimFactorsOf (DimOfUnit unit)) 'DefaultLCSU))
        arising from a use of ‘%’

This seems to be because I'm unsure of what the proper way of associating an appropriate LCSU is with my parsed UnitExp Data. Essentially the problem seems to be that I can't see a way of making a "runtime-type equivalent" to MkQu_ULN Unit LCSU Double, something like MkQuRunTime_ULN UnitExp LCSU Double.

So I suppose the question is: am I trying to do something too far counter to what the units/units-parser is designed for? Or is there some pattern I can apply so that I can get past the type checker and have the UnitExp -> Quantity evaluated at runtime.

Cheers.

Understanding the use of Double

I'm trying to understand how to get numbers into units. Currently, it seems like I must use Double for the quantities. But if I have some seconds in sec :: Int, and I want a Time, I'm doing fromIntegral sec % Second. Is that to be expected, or is there a better/different way?

Confusing type error because of bad fixity declaration

Consider a data type like this:

data Object lcsu vec = Object { m :: Mass lcsu (Scalar vec), v :: Velocity lcsu vec }

It is defined independently of the number of dimensions of its vectors.

Now, say you want to construct an Object like this (expanded to show the type annotations):

ve :: Velocity SI (Double, Double)
ve = (1, 1) % Meter :/ Second
ma :: Mass SI Double
ma = 1 % Gram
object = Object ma ve

The compiler will complain to you that (shortened):

    Couldn't match type ‘Qu
                           '['F Data.Dimensions.SI.Length One] lcsu0 (t0, t1)
                         :/ Second’
                  with ‘Qu
                          (DimFactorsOf Data.Dimensions.SI.Velocity)
                          (MkLCSU
                             '[(Data.Dimensions.SI.Length, Meter),
                               (Data.Dimensions.SI.Mass, Kilo :@ Gram),
                               (Data.Dimensions.SI.Time, Second),
                               (Data.Dimensions.SI.Current, Ampere),
                               (Data.Dimensions.SI.Temperature, Kelvin),
                               (Data.Dimensions.SI.AmountOfSubstance, Mole),
                               (Data.Dimensions.SI.LuminousIntensity, Lumen)])
                          (Double, Double)’
    Expected type: Velocity SI (Double, Double)
      Actual type: Qu
                     '['F Data.Dimensions.SI.Length One] lcsu0 (t0, t1)
                   :/ Second
    In the expression: (1, 1) % Meter :/ Second
    In an equation for ‘ve’: ve = (1, 1) % Meter :/ Second

The example solves this by creating the Vec2D type family, but I'm wondering if there is any way to solve this without giving up the dimension polymorphism mentioned above.

Type errors appear at wrong place.

Yesterday, I was able to locate the source of an error that have been haunting me for a while. First, please look at the following code. The function area1 is defined with correct unit, but is used with wrong unit in another function ratio . The type error is correctly reporting the unit error in the body of ratio.
https://github.com/goldfirere/units/blob/master/Tests/Compile/Error/Case1b.hs

However, if we make a slight modification to the above code, evil happens.
https://github.com/goldfirere/units/blob/master/Tests/Compile/Error/Case1a.hs

In Case1a.hs, the function modelNorm is defined with correct unit, but is used with wrong unit in another function. However, the error is reported at the point definition (which is nothing wrong) and not at the point of use. These kind of error message may cause the users to waste time looking hard for error in the functions, that contains no error (as I did.) Strangely enough, the error related to function area1 is also reported at wrong place in Case1a.hs, even though the source code parts related to area1 is not modified at all.

The only thing I can see that connects the two parts is the QofU type synonym. I can also reproduce the symptom using MkQu_ULN , a type synonym that belongs to units library.

https://github.com/goldfirere/units/blob/master/Tests/Compile/Error/Case1c.hs

I cannot figure out any further about this error. Is this a mis-design of the library (hard to believe,) or is it a GHC bug? The behavior reproduces on the latest ghc-7.8.3. Since this is beyond my understanding, Let me report and consult to upstream (first to @goldfirere and then maybe to the GHC team.)

Question: how to define a typeclass instance on different quantities

Hi,
I was porting some old code of mine where I implemented some custom parsers - yes, I am aware of units-parser but it doesn't quite fit my needs - and in this code I was probably abusing the type system for something that is no longer allowed (in 7.10.1). I've converted the types to Units 2.3, but still:

instance ParseUnit Meter (Qu (DimFactorsOf (DimOfUnit Meter)) 'DefaultLCSU Double) where
  parseUnit g = parseUnit' g

Still yields:
Illegal type synonym family application in instance: Qu ...

So, how can I declare class instances for quantities like (5 % Second), what should I use for the type?

Thanks

Write a TH linter

It is very easy to get dimension and unit declarations wrong, leading to terrible error messages. This feature request is to add a "lint" function, written in Template Haskell, to check unit and dimension definitions for sanity and report decent error messages.

extend makeQuasiQuoter Unit Types

Now that @goldfirere has implemented long-wanted qq-maker for creating unit expressions, I also want TH function for creating unit types.

However, my attempt to insert even basic Q Type s have been failed, although the type signature appears to be nothing wrong for me.

I must confess that I have little experience writing Template Haskells, and I need help.

Data/Metrology/Parser.hs:77:9:
    No instance for (Language.Haskell.TH.Syntax.Lift QuasiQuoter) ...

for 947e5d0

    No instance for (Language.Haskell.TH.Syntax.Lift (String -> Q Type))

for 2fc598a

Dimension for "Hertz"

The unit of "Hertz" is usually written 1/s, but I'm not sure that's what people really mean. I think Hertz is more usefully defined as cycles/second, where 1 cycle is 360 degrees, 2pi radians, 2 semi-circles, etc. So I think the right dimension for Hertz is angle/time. Is that sensible and consistent with common usage?

Swap `#` with `##`? (and same for `%`)

Right now, ## is monomorphic while # is polymorphic. This goes against the general design of making the monomorphic things more accessible than polymorphic things, as non-experts will want the monomorphic ones.

(Suggested by João Cristóvão)

Build fails with GHC 8.8

Building library for units-2.4.1.1..
[ 1 of 19] Compiling Data.Metrology.Set ( Data/Metrology/Set.hs, dist/build/Data/Metrology/Set.o )
[ 2 of 19] Compiling Data.Metrology.Z ( Data/Metrology/Z.hs, dist/build/Data/Metrology/Z.o )

Data/Metrology/Z.hs:70:3: error:
    Illegal visible type application ‘@PSym0’
      Perhaps you intended to use TypeApplications
   |
70 | $(singletons [d| data Z = Zero | S Z | P Z deriving Eq |])
   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Data/Metrology/Z.hs:70:3: error:
    Illegal visible type application ‘@SSym0’
      Perhaps you intended to use TypeApplications
   |
70 | $(singletons [d| data Z = Zero | S Z | P Z deriving Eq |])
   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Verify output from the Travel test

At the end of the Travel.hs test, there is a comment with expected output. Currently, on my machine, the output differs somewhat.

Expected output:

46.5 mi
40.0 mi/gal
7.29 lb/gal
8.474625 lb

74.834496 km
14.160249 km/l
0.7273698 kg/l
3.844025 kg

My current output:

46.5 mi
39.999996 mi/gal
7.29 lb/gal
8.474626 lb

74.834496 km
14.160248 km/l
0.7273698 kg/l
3.8440251 kg

Most alarming to me is the second line, with significant rounding error. In examining what's going on, though, this seems somewhat reasonable. The input is 40 mi/gal. Yet, according to the LCSU, this quantity is stored in terms of yards/(cubic yard) -- which is much larger. The precision-saving idea around using Rational doesn't really help here, because we are storing the large number between conversions. So, I think that the observed behavior can be considered correct, but I want a second opinion.

Include physical constants?

Should the units package define some set of useful physical constants? I tend to think "no", but I want to document the thought. It could even be argued that the SI definitions should be in a separate package.

Reorganize the names and modules.

Thanks to the initial joyful development, now the core features are settled but the modules are bit disorganized (as often happens). For example classes Dimension and Unit are both defined in Data.Dimensions.Units. The data type Dim defined in Data.Dimensions.Dim expresses quantity rather than dimension. Modules Data.Quantity.* are obsolete and are to be removed.

To save the future users and developers of units from confusion, I think I'll take a night and reorganize the modules. This kind of renamings come with pain and are always controversial, but if done at earlier stage less is the pain.

I'll first wait for any opinions.

Units not building with ghc 7.6.3

Building units-1.0.0...
Preprocessing library units-1.0.0...
[ 1 of 12] Compiling Data.Dimensions.TypePrelude ( src/Data/Dimensions/TypePrelude.hs, dist/build/Data/Dimensions/TypePrelude.o )

src/Data/Dimensions/TypePrelude.hs:25:63:
parse error on input `where'

$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.6.3

I can't seem to find what version of GHC introduced these closed type families.

Add export list to Z

The Haddock docs for the Z module include some singletons-related gubbins. An export list would squelch this.

Kinds of Quantities

All the schemes described above, use a simplified representation of physical types, and do not incorporate ‘kind-of-quantity’ (KOQ), which is another attribute [7] of a physical type, at a higher abstraction than dimension. Thus, two quantities may have the same dimensions, but can be different kinds of quantities. Familiar examples are energy and torque, both of dimension ML2T-2, and heat capacity and entropy, both of dimension ML2T-2Θ-1.

https://www.researchgate.net/publication/326550053_Physical-type_correctness_in_scientific_Python

Is it possible with this units package to e.g. prevent addition of a value of type torque to a value of type energy?

Relationship of Time to NominalDiffTime

I'm just leaving this here as I ponder it. Food for thought, so to speak.

I wanted to use Time instead of NominalDiffTime, so I came up with:

import qualified Data.Time.Clock as C
addUTCTime :: Time -> UTCTime -> UTCTime
addUTCTime d = C.addUTCTime (realToFrac (d # Second))

Again, this has to do with conversions, as mentioned in #19. I'm not sure if there's a better way to do this.

As I use units and units-defs more, I realize that unit-polymorphism, as you call it, is useful but a lot of other libraries rely on specific units (e.g. microseconds for threadDelay as @jcristovao has wrapped in unbounded-delays-units and seconds with picosecond resolution for NominalDiffTime). Perhaps when you revisit this library, you can think about conversion between quantities of a particular unit and unit-polymorphic quantities. Or maybe we just use fromIntegral and realToFrac.

Consider introducing `:#` to control `Show` instances

nushio3 says:

I'm thinking of introducing a type constructor

data q :# u
instance Show (q:#u) where show (q:#u) = showIn q u

which is essentially a tuple of a quantity and a unit, designating that we want to associate the quantity with the specified unit.

(Copied from #12, where this is less relevant.)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.