GithubHelp home page GithubHelp logo

bjornbm / dimensional Goto Github PK

View Code? Open in Web Editor NEW
102.0 102.0 16.0 751 KB

Dimensional library variant built on Data Kinds, Closed Type Families, TypeNats (GHC 7.8+).

License: BSD 3-Clause "New" or "Revised" License

Haskell 100.00%

dimensional's People

Contributors

bjornbm avatar dmcclean avatar kommusoft avatar konsumlamm 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  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dimensional's Issues

Name the type of angle that is constrained to lie within a single revolution

Given that Angle already names the type of arbitrary angles, what is the best name for the type of angles that are constrained to lie within a single revolution? (Alternately, the type of angles that are equated if they differ by an integer number of turns.)

Both types are all over the place.

We should keep Angle for the one it denotes now, for consistency with the way we treat Time and Temperature and so forth as unbound from any particular distinguished origin.

Continuous integration

Are there any objections to setting up this repository to use travis-ci?

Because it's open source, it's free, and their server will automatically run the build and tests (once we fix them) after each commit. It also runs it on each PR so that you can see whether merging it will break the build before you decide.

I can set up the configuration, but only the repository owner can actually turn it on. As a result, @bjornbm would need to sign up for an account on travis-ci.org using his github account and grant certain permissions to their servers.

If we decide to do this you can sign up at any time, but probably shouldn't flip the on switch until we have the configuration file in place.

Explicit kinding of type families?

Example: (where this issue is already flagged)

type family a * b where -- constrain kinds??
  (Dim l m t i th n j) * (Dim l' m' t' i' th' n' j')
    = Dim (l + l') (m + m') (t + t') (i + i') (th + th') (n + n') (j + j')

On my reading of the relevant docs, that the correct kind (Dim -> Dim -> Dim) will be inferred for closed type family declarations of this form. I can't confirm this because my GHC 7.8 install isn't working yet.

Nevertheless it might be desirable to write them out explicitly for the sake of new readers.

Functor

In #29 and #19 we discussed whether the Dimensional constructor should be exposed, and whether to have a Functor instance.

We came down on the side of no, which I strongly agree with, because it breaks the abstraction. We exposed dmap from DK but not DK.Prelude so that people could get at this if they wanted to, but wouldn't get it by default.

I now propose that we add a Functor instance, but put it in a separate module.

{-# LANGUAGE OverlappingInstances #-}
{-# OPTIONS_GHC -fno-warn-orphan-instances #-}
module Numeric.Units.Dimensional.DK.DubiousFunctorInstance where

import Numeric.Units.Dimensional.DK

instance Functor (Dimensional v d) where
  fmap = dmap

The purpose of this is to empower users to make the choice for themselves. One specific reason for making such a choice would be to be able to get along with Edward's linear package.

Splitting into multiple units

For some of the legacy units it would be nice to have functionality like that of (/~) which in some sense "splits" a quantity into multiple units.

Something like:

split :: (RealFrac a, Integral b) => (Unit d a, Unit d a) -> Quantity d a -> (b, a)
split (a, b) x = -- something that involves properFraction

so that split (foot, inch) (12.37 *~ meter) evaluates to (40, 7.00787) because 12.37 meters is 40 feet 7.00787 inches.

Also would like the same thing but for triples, split3 :: (RealFrac a, Integral b) => (Unit d a, Unit d a, Unit d a) -> Quantity d a -> (b, b, a) for converting to degrees/minutes/seconds of arc.

One hairy thing is that it's unclear what the semantics should be when the second unit is larger than the first. I suppose it makes some sense to allow split (foot, mile) (12.37 *~ meter) to be (40, 0.000110604). Nobody would ever want to do it on purpose, but it isn't actually wrong.

Is there a way to not need units?

It's possible to imagine a flavor of this library where the Variant concept is eliminated, there are only quantities, and units don't exist.

It seems like this would be simplifying and desirable, except for two things:

  1. Introduction/elimination of Dimensionless-ness.
    • Introduction can probably be fixed, perhaps more nicely at least for client modules which pervasively use dimensional-dk, by making a (Fractional a) => Fractional (Dimensionless a) instance and the corresponding fromRational function.
    • You could consider using another fromRational function instead, if you strongly dislike the Prelude numeric type hierarchy (which certainly leaves a lot to be desired). Rebindable syntax makes this pretty painless, but there is the question of which alternative hierarchy to use. You could also consider just making a non-type-class fromRational function for dimensionless, and using only that in dimensional-dk client modules, I suppose.
    • Once you do that, you don't need *~ and /~ anymore, because 6.3 * meter now promotes the 6.3 to (Fractional a) => Dimensionless a, and meter is (Num a) => Quantity DLength a.
    • But elimination is another question. Dividing by your (now just a quantity) unit would get you as far as, e.g. Dimensionless Double, but to get back to a raw Double you need another step. extractValue :: Dimensionless a -> a (or unD or something) is possible. But is the noise of that worth the benefits of getting rid of unit vs quantity?
    • Is the new coerce function already this elimination operator? I think it might be, because all the hypothetical extractValue function does is unwrap the newtype.
  2. Unit prefixes.
    • One might argue that it feels unhygienic to allow kilo and friends to apply to general quantities.
    • We maintain "Unacceptability of stand-alone prefixes". And just as now we sorta do and sorta don't have "Unacceptability of compound prefixes" (depending on whether you count composing them with . or parenthesees). But we lose "Unacceptability of stand-alone prefixes".

There are a lot of pros and cons, so it almost feels like a coin flip.

The fact that units might have an important static role to play (in constructing useful fixed-point quantities) is another thing to consider.

"Circular" units: are they generative the way square/cubic ones are?

Electricians in the US use a fairly bizarre unit called the circular mil, defined to be the area of a circle one mil in diameter. (A mil, in turn, being 1e-3 inches.)

We have square and cubic. Logically circular could be in the same category, which would be consistent. But I've also never heard of anyone else anywhere on earth using circular anything-besides-mil as a unit.

It's basically pi / 4 times whatever square would give you.

Documentation style

What is the policy on documentation style?

Right now we have some .lhs files written in a bird-tack markdown style and some .hs files with markdown in block comments.

Are you using pandoc to process the markdown into something? If so, can you share a script for invoking it as you do so that contributors can be sure not to break it?

It's presumably desirable to have haddock comments as well. Or is it? If so, how do we make those coexist with the literate markdown? I tried researching this and found this StackOverflow question. The answers are informative and interesting, but AFAICT don't actually answer the most direct part of the question, which I would phrase as "what is the example syntax of a haddock commented declaration that will be acceptable to both haddock and the literate markdown processor?".

Type checker plugin

(Warning, this is a doozy.)

It would be really nice if we had a type checker plugin capable of solving constraints like d ~ DOne / (DOne / d) and other "obvious" proof obligations that arise.

These sorts of things were crippling to the first attempt at using this for dimensional linear algebra, and especially for dimensional linear algebra as it applies to control theory. (Some of those sketches using dimensional-dk are no longer visible in history at that link.)

It turns out that unification in abelian groups (like the group of dimensions) is decidable, and that unification discharges all of these things that we think are obvious, and a few more besides. The agum package provides a Haskell implementation (unfortunately with GPL licensing) of this that could be used to do "the hard part" of this problem. Of course, the actual hard part is figuring out how the GHC type checker plugin API works. ;)

Haddock link issues

It seems that every link to Pos1 of the documentations on Hackage tries to link to c:/Users/Doug/AppData/Local/GitHub/PortableGit_c2ba306e536fdf878271f7fe636a147ff37326ad/package/numtype-dk-0.5/docs/Numeric-NumType-DK-Integers.html#v:Pos1; the same goes for Zero, etc.

Value of mmHg

There seems to be some dispute over the value of the millimeter of mercury column.

master

prefix 13.5951 (gram * centi meter ^ neg3 * milli meter * gee)

UCUM, on their own authority or at least without a footnote

Table 18: Units Used Predominantly in Clinical Medicine meter:

meter of mercury column = 133.3220 kPa
so mmHg = 133.3220 Pa

NIST Guide

Table 9: Other non-SI units accepted for use with the SI either by the CIPM and this Guide (indicated by_), or by this Guide (indicated by_*)

mmHg = 133.322 Pa

Wikipedia, citing the British Standards Institution

A millimeter of mercury is a manometric unit of pressure, formerly defined as the extra pressure generated by a column of mercury one millimetre high and now defined as precisely 133.322387415 pascals. [1]

(seriously? 12 places? 😡)

Discussion

I assume we agree that the BSI can pound sand? I'd like to match the UCUM definition so that our parser can be compliant, thankfully they agree with NIST.

On *~, /~, and the missing unnamed operator

The *~ operator basically converts its first argument into a dimensionless quantity and then calls the * operator.

The /~ operator basically does \ and then strips the Dimensional constructor off the dimensionless result.

Unfortunately there is no operator that converts its second argument into a dimensionless quantity and then calls the \ operator. flip $ (*~) . recip, but with a type that doesn't require a Unit the way that *~ (somewhat unfortunately, see the named-units branch) does. And I am having trouble coming up with a name for it that makes sense and aligns with the existing two.

Not having this operator seems to account for the lion's share of my use of _2, _3, etc. (Not _1, and _0, which are good for a thousand other things.)

Pursuant to the comment above about the type of *~: If the named-units branch is too radical, how do you feel about relaxing the type of *~ from:

(*~) :: Num a => a -> Unit d a -> Quantity d a
x *~ Dimensional y = Dimensional (x Prelude.* y)

to

(*~) :: Num a => a -> Variant v d a -> Quantity d a
x *~ Dimensional y = Dimensional (x Prelude.* y)

Are units ordered?

Right now we have Eq and Ord instances for Dimensional, so we have one for Ord a => Unit d a.

Is this desirable or objectionable? AFAICS, the NIST guide doesn't say anything about it one way or the other.

(Asking because it isn't automatic in the land of named units.)

Generalize dimensionlessLength

Now that Foldable is in the prelude, can we generalize dimensionlessLength :: Num a => [Dimensional v d a] -> Dimensionless a to (Foldable f, Num a) => f (Dimensional v d a) -> Dimensionless a?

Unit parsing

Following on to #7, the flip side to pretty-printing is parsing.

Unfortunately the SI unit notation and names have several ambiguities, documented (perhaps not extensively) by this article.

Nevertheless, we need not let that discourage us. We can either pick conventions, or report the ambiguities if the arise, or disambiguate them because we know what dimension we were expecting the user to enter in that field, or some combination of those strategies.

Alias DImpulse as DMomentum?

AFAICS we don't have a dimension alias for translational momentum, only for angular momentum. It's the same as the one currently called DImpulse.

Can I add an alias or am I missing a reason why this is a bad idea?

Alias of DMomentOfForce

The NIST Guide uses "moment of force", and so dimensional correctly follows that name.

I think that the name "torque" is also commonly used for the same concept, and that it would improve discoverability for new users if this name was also acceptable.

I therefore propose the addition of the following alias:

type Torque = MomentOfForce

Whether to also add:

type DTorque = DMomentOfForce

... should probably follow the same decision as that for Angle, Thrust, and EnergyPerUnitMass, which is commented as up in the air at the bottom of the Quantities file. (I would vote for adding both, personally.)

Separate dimensions and dimension arithmetic into its own module

Can we separate Dimension and Dimension' and all the type-level operators on dimensions into their own module? It would result in cleaner documentation, shorten the main module, and could be re-exported by 'Numeric.Units.Dimensional.DK' so that clients wouldn't need to care.

Removing dimensionlessLength, *~~, and /~~?

I don't think dimensionlessLength really gets us much, since we have mean?

I also think that operator sections allow fmap (*~ meter) xs is at least as readable as xs *~~ meter without another operator name to remember.

Retire variants?

#2 started out being mostly about removing the distinction between quantities and units. I was reluctant then, saying:

Separating units and quantities was a very conscious decision, and one that I am quite happy with and feel has worked quite well in practice (YMMV). Converting quantities to values is performed, by necessity, very close to NIST guidelines (see 7.1 and 7.8) and I think this is a good thing.

Now, in light of e.g. #38, I'm reconsidering. Perhaps the added complexity of separating 'Quantity' and 'Unit' is not worth the extra complexity (Variant phantom type) and occasionally convoluted workarounds (e.g. Prelude. uses) that it can cause.

Relaxing would allow some ugly stuff:

x = kilo (meter + mile)
y = second * x

But even the current design isn't perfect with regards to NIST, allowing, e.g.:

u = kilo (kilo (meter / second))

so I'm not sure it is worth defending.

I would like to hear if you, Doug, have had any more thoughts on this topic. I know that you have actually gone even further with the distinction in the named-units branch, and imagine the impact would be treating everything as a unit (i.e. keep tracking the unit name) until multiplying with a Num (e.g. with (*~)).

Monoid instance

Making a Monoid instance for quantities doesn't suffer from the ambiguity that led to the Sum/Product newtypes because, unless d is DOne, summing is the only obvious monoid over quantities.

I therefore proposing adding a monoid instance that sums quantities.

(I will submit a patch later when I get to a computer with GHC 7.8.)

Benchmark suite

Add benchmarks measuring to make sure that the things we think are getting erased are actually getting erased in practice.

Dimension of action?

In experimental's Codata module we had:

-- Alias this dimension as DAction? Seems rarely used?

planckConstant :: (Fractional a) => AngularMomentum a
planckConstant = 6.62606957e-34 *~ (joule * second)

This definition doesn't compile under the angular branch, because of the missing radians.

Seems the correct solution would be to add DAction and Action to the Quantities module? Just checking because I've never been really clear on what this constant is about, and the wikipedia page explaing action is ... perplexing.

Remove time dependency

There is a dependency on the time library to for the toDiffTime and fromDiffTime functions. The functions are trivial enough that the dependency probably isn't justified. I propose removing the dependency.

(We could keep the functions with the same name but relax the types to any Real/Frac instead of DiffTime. The intent would hopefully be clear, but not enforcing it with the type is a bit iffy.)

Alternate approach for named-units

Starting a new issue to not add another thread to #46.

@dmcclean wrote:

I forgot to comment on internationalisation. I think that it might be best served by going from UnitName to UCUM and allowing people to internationalize by coming back out again? Direct structural recursion on UnitName is another possibility, but our name and abbreviation choices for non-SI units are arguably less standard.

I don't follow exactly what you envisioned in the first suggestion above. But yesterday evening I also had an idea about structural recursion and have drafted the https://github.com/bjornbm/dimensional-dk/tree/typenames branch.

The most interesting modules are UnitNames and I18N, but there are also some changes elsewhere including a change of the Dimensional type in DK.

Type level "canonical" (our arbitrary choice) unit names are attached as ASTs to Units. When the unit is to be shown the type level AST is converted to a value level AST. The mechanics for this is in UnitNames.

The string representations for units and prefixes in the value level AST can then be translated to other language by use of a Map. See I18N, which also has the non-internationalised showUnit and showIn.

If you load I18N you get the prelude too (right now) and can play around a little in ghci.

*Numeric.Units.Dimensional.DK.I18N> let x = 10 *~ (meter / second ^pos2)
*Numeric.Units.Dimensional.DK.I18N> x
10.0 m s^-2
*Numeric.Units.Dimensional.DK.I18N> showIn (kilo meter / second ^ pos2) x
"1.0e-2 km/s^2"
*Numeric.Units.Dimensional.DK.I18N> showIn (second ^ neg2 * kilo meter) x
"1.0e-2 s^-2 km"
*Numeric.Units.Dimensional.DK.I18N> long en_us (kilo meter / second ^ pos2)
"kilometer/second^2"
*Numeric.Units.Dimensional.DK.I18N> long en_gb (kilo meter / second ^ pos2)
"kilometre/second^2"
*Numeric.Units.Dimensional.DK.I18N> long sv_se (kilo meter / second ^ pos2)
"kilometer/sekund^2"
*Numeric.Units.Dimensional.DK.I18N> short sv_se (kilo meter / second ^ pos2)
"km/s^2"
*Numeric.Units.Dimensional.DK.I18N> showUnit (kilo meter / second * second)
"km/s*s"
*Numeric.Units.Dimensional.DK.I18N> showUnit (kilo meter / (second * second))
"km/(s s)"
*Numeric.Units.Dimensional.DK.I18N> showUnit (one * second)
"s"
*Numeric.Units.Dimensional.DK.I18N> showUnit (one / second)
"1/s"

I haven't thought through all corner cases there might be.

I haven't thought through naming very much, mostly just used what occurred to me first.

I've based the AST around your UnitName data type. The reason for Atomic and PrefixableAtomic eludes me but I kept them all the same as I'm sure you have thought things through. I didn't do any research either: perhaps someone (UCUM?) already has designed the perfect AST for describing unit presentation?

Most units and prefixes are missing from SIUnits, and even fewer (kilo, meter, second) are in I18N.

Does this approach have merit?

(The code could clearly use more documentation, and perhaps som restructuring in places. If it is too opaque for you to judge let me know and I'll try to document better.)

Choose pattern for torsor newtypes

Temperatures and times present a few challenges. The SIUnits module deals with one of them by:

fromDegreeCelsiusAbsolute :: Fractional a => a -> ThermodynamicTemperature a
fromDegreeCelsiusAbsolute x = x *~ degreeCelsius + 273.15 *~ degreeCelsius
toDegreeCelsiusAbsolute :: Fractional a => ThermodynamicTemperature a -> a
toDegreeCelsiusAbsolute x = (x - 273.15 *~ degreeCelsius) /~ degreeCelsius

I think this is not ideal because it encourages people to store absolute temperatures in ThermodynamicTemperature a form.

Having newtype AbsoluteTemperature a = AbsoluteTemperature (ThermodynamicTemperature a) somewhere seems like a good idea from a documentation perspective, and also allows checking conversions between various absolute scales.

Similar issues arise when tracking times, but they are even worse because the universe wasn't nice enough to supply us with an easily accessible "absolute". As a result, code with precision timekeeping needs generally requires not one but several newtypes for absolute times.

It would be nice if the core dimensional package addressed these concerns (at least the temperature one) to facilitate interoperability among other libraries developed on top of it.

I'm not sure if this can be addressed parametrically, or if it is better addressed by just laying down a pattern to be copied at each monomorphic concept where it is needed.

One possible idea (reserving comment on its merits):

newtype DimensionalTorsor (d :: Dimension) (n :: Symbol) (a :: *) = Torsor (Quantity d a)
difference :: DimensionalTorsor d n a -> DimensionalTorsor d n a -> Quantity d a
offset :: DimensionalTorsor d n a -> Quantity d a -> DimensionalTorsor d n a

type AbsoluteTemperature = DimensionalTorsor DThermodynamicTemperature "AbsoluteTemperature"
type UtcTime = DimensionalTorsor DTime "UTC"
type TaiTime = DimensionalTorsor DTime "TAI"
-- and so forth

Unfortunately this doesn't provide an opportunity for validation/canonicalization, so for example uses of offset can result in negative AbsoluteTemperatures. (Which, while it might make sense in itself, does not make sense as being offset from a nearby positive temperature, AFAIUI.) Typeclass pixie dust could remedy this defect, if it was thought to be worth it.

(There is a related issue for angles, where there is a commonly needed newtype that treats Angle a values as equivalent when they are separated by an integer number of turns. Addressing that may or may not be done using similar techniques.)

named-units raison d'être?

@dmcclean, I've reviewed your named-units-variants branch and lite this iteration better. However, as I asked in #7 regarding the named-units branch:

Just to make sure we're on the same page: exactly what is the problem we are trying to solve (here)? To provide the UnitMap functionality? Any other goals of the named-units branch?

Can you provide a concrete use case (perhaps pseudo-code) of what named-units will enable that cannot be handled by other means (e.g. a specialised show function taking a map of desired units)? Thanks

Documentation style

Right now a couple of the files are literate haskell with markdown (I think?) comments in the bulk of the files. The others are ordinary haskell files with markdown (again, I think) comments.

One drawback to this state of affairs is that we don't have haddocks.

@bjornbm, do you have tools you use to process the markdown to create PDF or HTML documentation from files in this style? I assume such tools are out there, but I'm having trouble figuring out which if any are in active use by the community.

I'd lean towards voting for ordinary .hs style with haddock documentation. Some of the current explanatory discourse could move to named chunks and appear at the appropriate place in the export lists. Others could sensibly be attached to individual definitions. Still others might (I'm not sure) be better demoted to ordinary comments that aren't visible in the exported documentation.

If we make the other choice, I'd vote for doing it across the board, and for writing haddocks at least for the non-obvious things.

Either way, I'm happy to do the busywork of converting to whatever style is chosen.

Updates to the NIST Guide

The current version of the NIST guide at http://physics.nist.gov/Pubs/SP811/, where the documentation links point, appears to have been updated compared to when the documentation was written.

Several tables have changed names.

Also table 3 (the part at the end that was formerly in 3b) has added the katal (1 mole/second) as a unit of "catalytic activity". Do we have a specific objection to adding this, including the unit, dimension, and quantity aliases?

Plane and solid angles as base dimensions?

See the issue and comments posted by fredhpitts at: https://code.google.com/p/dimensional/issues/detail?id=43

They have been copied below for posterity(?) as google code is going away next year.

@dmcclean feel free to add your thoughts here as well!


Issue 43: Plane and solid angle inconsistencies in dimensional-tf

Reported by fredhpitts, Apr 12, 2015

What steps will reproduce the problem?

  1. Edit TF.lhs and Quantities.lhs to add plane and solid angles to the 7 base dimensions.
  2. Attempt to compile and execute Test.hs

What is the expected output? What do you see instead?
Expect Test.hs to compile and run successfully. Test.hs does not compile because

  1. in SIUnits.lhs, lumen' should be defined ascandela * steradian' not `candela / steradian' (see luminus flux entry of Table 3 at http://physics.nist.gov/cuu/Units/units.html)
  2. in Quantities.lhs, DAngularVelocity should be defined as plane angle per time, not DFrequency, which has dimension of reciprocal time.
  3. in Quantities.lhs, DRadiantIntensity should be defined as having the dimensions of power divided by solid angle
  4. in Quantities.lhs, DRadiance should be defined as having the dimensions of irradiance divided by solid angle

What version of the product are you using? On what operating system?
dimensional-tf-0.3.0.1 downloaded with cabal. Fedora 20

Please provide any additional information below.
I fully appreciate that only item 1) above is an error and that the remaining three items are a consequence of plane and solid angles being added to the list of primary dimensions. But taken as a whole, the items highlight the danger of not adding plane and solid angles to the list. Even though dimensionless, they are physical quantities with various units of measure (radian, degree, grad, steradian, square degree, etc) that can easily get lost or misused as in item 1).


Apr 24, 2015 #1 bjorn.buckwalter

Thanks for the report. I have fixed the definition of lumen.

However, I have to decline the request for adding plane and solid angles as base dimensions. Doing so would not be consistent with the SI and I believe it would likely introduce as many problems and ambiguities as it would remove. For example, should dividing two lengths result in a Dimensionless or a PlaneAngle? I recommend wrapping your angles in newtypes when you are particularly concerned about mixing them up or misusing them.

Status: Fixed


May 9 (3 days ago) #2 fredhpitts via email

The answers to "should dividing two lengths result in Dimensionless' or a PlaneAngle" are: 1)Dimensionless' if you have no need to know how the dimensionless number came in to being in subsequent computation.
2) A ratio of lengths if you're dealing with ratios of mass, for instance, in subsequent computation. Adding length ratios and mass ratios is as much a dimension error as adding length and mass quantities. And even addition of length ratios is meaningless if the length ratios are not on the same basis.
3) The only circumstance in which dividing two lengths should result in a PlaneAngle is when the numerator is the distance along a circle arc and the denominator is the radius length of the same circle.

Case 3 above is the exception and should be handled as such (i.e. wrapped in a function). Being consistent with SI is laudable, but ignoring the issues that are not dealt with by SI will significantly restrict the usefulness of dimensional consistency software. I think blind canceling of dimensions during multiplications and divisions is a fundamental mistake. Finesse is needed here so as to not loose valuable information.

BTW, at one time PlaneAngle and SolidAngle were recognized as secondary dimensions in SI. For whatever reason they were deprecated. That does mean they not important to implementing dimensional consistency software. I dare say you would not have made the error in the lumen implementation if SolidAngle had been rigorously accounted for by the code. Isn't the point of dimensional consistency software to prevent such errors.

Furthermore dimension consistency software needs to address vector and affine quantities which SI says nothing about.[?]


Today (moments ago) #3 bjorn.buckwalter

Thanks again. I appreciate you taking your time and effort writing this. I agree with you in principle, and you are absolutely correct that the error in lumen would have been avoided if SolidAngle was tracked in it's own base dimension.

On the other hand I don't think it is an easy problem to solve, with an obvious implementation and API. As you say: finesse is needed to make it work well. But if you are willing to help draft one we could consider adding it.

FYI current and future development of dimensional is being performed on the not-yet-on-hackage dimensional-dk (https://github.com/bjornbm/dimensional-dk) that is intended to supersede dimensional and dimensional-tf. Nowadays my co-maintainer Douglas McClean (https://github.com/dmcclean) actually does most of the work on improving and expanding functionality, and he is quite sympathetic with your concerns. If you are interested in contributing I suggest that you continue the discussion of what a possible implementation could look like with him on Github while I follow from the side-lines. I've copied our conversation here to #72 for further discussion.

Num vs Fractional context for the SI coherent derived units

We have, choosing one example arbitrarily:

pascal :: Fractional a => Unit DPressure a
pascal = newton / meter ^ pos2

But we could have:

pascal :: Num a => Unit DPressure a
pascal = siUnit

because we know that, as a coherent unit, it's value is 1. The cost is a less self-explanatory definition, which could be addressed by comments?

(This question arises more acutely in the branch that tracks exact conversion factors, but even without that feature it is an interesting question IMO.)

Customizable unit pretty-printing

Following on to #5, it would be nice to have a term-level representation for units that binds the dimension, value, abbreviated name, and full name.

Suppose this type is something like (though there are probably better names):

type UnitValue (d :: Dimensions) = forall a.(Num a) => Unit d a
data UnitInfo (d :: Dimensions) = UnitInfo (UnitValue d) String String -- value, abbreviation, name
type AnyUnitInfo = forall (d :: Dimensions).UnitInfo d

Then you could have a Map Dimension AnyUnitInfo that listed your preferred units to be displayed for every dimension you feel you are likely to encounter. This would be a powerful tool for formatting your output.

It would add value beyond the current Show instance for dimensional values because it would:

  1. Show familiar units for dimensional quantities whose dimension is not an SI base unit. e.g. "1.624 W" instead of "1.624 m^2 kg s^-3".
  2. Provide both full and abbreviated names.
  3. Remove the unit names from the basic module and move them to live with the definitions of the corresponding units in the SIUnits module.

Replace Dimensional constructor with siUnit?

We have discussed whether the Dimensional constructor should be exposed (see #19). It is occasionally useful, but I think it could be replaced by:

siUnit :: Num a => Unit d a
siUnit = Dimensional 1

Using fmap as an example:

fmap f x = f (x /~ siUnit) *~ siUnit

See any problems or loopholes with siUnit?

(siUnit was siBaseUnit but that was a misnomer as it may be either a base SI unit or a derived SI unit.)

Dimensional random variables

Have you looked at the intersection between dimensions and randomness? The (strangely named) random-fu package seems to be popular and reasonably comprehensive.

It would be nice to have a RVar (Length Double) instead of an RVar Double that I happen to know is in feet, but for some reason I can't think of the right way to get there from here.

Some desirable things would be:

  • Not requiring exposing the newtype constructor of Dimensional.
  • Not requiring dimensional-dk to take a dependency on random-fu or vice versa, but instead able to be define in a new package, say dimensional-random.

Fixity of `*~`, `/~`

I'm a little hazy on how GHC's fixity declaration system works.

Is there any way we can make it so we can write:

1 *~ poundForce / inch ^ pos2

instead of

1 *~ (poundForce / inch ^ pos2)

Or would it make something horrible happen in some other sort expression?

Exact conversion factors

Would they be worth taking a dependency on the exact-pi library (which itself only depends on base)?

This question only really applies to the named-units branch, because it requires all the same machinery for making Unit a data type while keeping Quantity as a newtype. It arises for the same reason (wanting to add extra runtime information to units).

It's one of the first steps in a long road that leads to useful fixed point quantity types.

Dimensions is mis-named?

I think there is merit to replacing:

data Dimensions = Dim NumType NumType NumType NumType NumType NumType NumType

with:

data Dimension = Dim NumType NumType NumType NumType NumType NumType NumType

This is because an instance of this type represents a dimension. The fact that it is constructed of some other dimensions, usually, unless it is DOne, is operationally important but shouldn't guide the choice of name.

Changing it to the singular would make kind signatures that use it, which will be all over the place in the linear algebra package, easier to understand.

Use type families in Quantities?

Type families have opened up the possibility of rewriting the Dimensions using type families. Examples:

type DArea = DLength * DLength
type Area  = Quantity DArea

type DVolume = DLength ^ Pos3
type Volume  = Quantity DVolume

I feel this could be instructive, but perhaps detrimental to the searchability for suitable Dimensions, so I'm not sure if it is a good idea or not.

Either way I don't want to make this kind of change at this time as it would severely reduce the portability to/from dimensional-fd. Perhaps when dimensional-fd has been deprecated in favor of dimensional-dk and I stop maintaining it.

Typeable representation for dimensional values

It would be great if we could use dimensional values in combination with the Data.Dynamic module.

The problem right now is:

<interactive>:79:1:
No instance for (Typeable 3) arising from a use of `toDyn'
In the expression: toDyn w
In an equation for `it': it = toDyn w

It's related to GHC ticket 8778.

This might be an argument for holding off on the switch to GHC's built-in type-level naturals.

Are negative units allowed?

Is there any sense to allowing negative units, e.g. definitions of the following form:

negawatt :: Unit DEnergy
negawatt = prefix (-1) (mega watt)

I don't believe there is. I am contemplating a change that would make it less fully supported, and I'm wondering if perhaps it should be banned outright as unexpected and a potential trap.

AFAICS, the NIST Guide doesn't have anything to say about this. The UCUM disallows it, see http://unitsofmeasure.org/ucum.html#section-Syntax-Rules.

Extraction of term-level dimensions

The Show instance for Quantity includes some code which essentially extracts a term-level description of a dimension.

I would like to see this split explicitly into two phases, because I have other planned uses for the term-level description. (For example, it is useful when the dimension parameter of Quantity is existentially qualified, if we are writing code that is working with quantities but doesn't know their dimensions.)

instance ( ToInteger (NT l)
         , ToInteger (NT m)
         , ToInteger (NT t)
         , ToInteger (NT i)
         , ToInteger (NT th)
         , ToInteger (NT n)
         , ToInteger (NT j)
         , Show a) =>
  Show (Quantity (Dim l m t i th n j) a)
    where
      show (Dimensional x) = let units = [ dimUnit "m" (undefined :: NT l)
                                         , dimUnit "kg" (undefined :: NT m)
                                         , dimUnit "s" (undefined :: NT t)
                                         , dimUnit "A" (undefined :: NT i)
                                         , dimUnit "K" (undefined :: NT th)
                                         , dimUnit "mol" (undefined :: NT n)
                                         , dimUnit "cd" (undefined :: NT j)
                                         ]
                             in unwords (show x : catMaybes units)

Can we instead have a function whatIsMyName :: forall (d :: Dimension).Proxy d -> Dimensions? The show function would then convert Dimensions to [Integer] in the obvious way, and then to [Maybe String]?

toSIBasis :: Dimensions -> [Integer]
toSIBasis (Dimensions l m t i th n j) = fmap N.toInteger [l, m, t, i, th, n, j]

It may be the case that Data.Proxy and/or the Sing typeclass in GHC.TypeLits is the correct way to write the function that gets you from a type-level Dimensions to a term-level Dimensions, but it is apparently too late at night for me to figure that out. I think I once knew but I can't dig it up now.

User manual

I am making a LaTeX user manual.

Requested content includes:

  • How to interoperate with this, that, and the other thing
  • Comparison of dimensional to other Haskell packages aimed at the same goal

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.