goldfirere / units

The home of the units Haskell package
94 stars 19 forks source link

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

Closed hesiod closed 9 years ago

hesiod commented 9 years ago

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! :smile:

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
goldfirere commented 9 years ago

Yes, you're right. But I'm not convinced this is a bug -- Points really can't be scaled. When you say that, say, an object has location (1 m, .2 m), you're really saying that the displacement of that object from some origin is (1 m, .2 m).

But I see how this makes the concepts difficult (impossible?) to use. Do you have a better design in mind?

hesiod commented 9 years ago

What about a quOf operator for affine spaces that only supports canonical units? Something like

quOfP :: forall unit dim lcsu n.
         ( ValidDLU dim lcsu unit
         , IsCanonical unit
         , AffineSpace n )
      => n -> unit -> Qu dim lcsu n
quOfP d u
  = Qu d

(%.) = quOfP
goldfirere commented 9 years ago

Maybe I'm being a stick-in-the-mud here, but I don't like singling out canonical units in this way. As far as the type system is concerned, the choice of canonical units should be utterly irrelevant. (Specifically, my goal is: the choice of canonical units may only be observed through rounding errors.)

This needs to be addressed. But I have a major deadline in 10 days (gasp!) and want to give this proper thought, which I can't at the moment -- sorry.