goldfirere / units

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

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

Closed DougBurke closed 9 years ago

DougBurke commented 9 years ago

{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))
DougBurke commented 9 years ago

After sleeping on it, I realise that it doesn't make sense to create a Show instance for a "derived" unit, such as AstronomicalUnit above. However, I still see the problem when creating a new dimensional unit (e.g. goldfirere/units-defs#10), which looks like it's working but I'm not 100% convinced is correct/sensible:

:set -XDataKinds

data AngleDim = AngleDim

instance Dimension AngleDim where
  type DimFactorsOf AngleDim = '[]

type instance DefaultUnitOfDim AngleDim = Radian

data Radian = Radian
instance Unit Radian where
  type BaseUnit Radian = Canonical
  type DimOfUnit Radian = AngleDim
  type UnitFactorsOf Radian = '[]

data Degree = Degree
instance Unit Degree where
  type BaseUnit Degree = Radian
  conversionRatio _ = realToFrac (pi / 180.0)

data ArcMinute = ArcMinute
instance Unit ArcMinute where
  type BaseUnit ArcMinute = Degree
  conversionRatio _ = (1/60)

data ArcSecond = ArcSecond
instance Unit ArcSecond where
  type BaseUnit ArcSecond = ArcMinute
  conversionRatio _ = (1/60)

then I can say things like

0.4 % Radian
24 % ArcSecond

and get back the expected values (e.g. 0.4 and 1.164e-4 aka 24*pi/(3600*180)). If I now add a Show instance:

instance Show Radian where
  show _ = "rad"

then I see the same problem as before, namely

0.4 % Radian
Could not deduce (Unit Radian) arising from a use of ‘%’
from the context (Fractional n) bound by the inferred type of it :: Fractional n => Qu '[] 'DefaultLCSU n at :1:1-12
In the expression: 0.4 % Radian
In an equation for ‘it’: it = 0.4 % Radian
DougBurke commented 9 years ago

This may be an IHaskell issue since it doesn't seem to happen from with ghci. I'll open a ticket over there and link it back.

% cabal repl
GHCi, version 7.8.4: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :set prompt "ghci> "
ghci> :set -XTypeFamilies
ghci> :set -XDataKinds
ghci> import Data.Metrology
ghci> import Data.Metrology.SI
ghci> import Data.Metrology.Show
ghci> data AngleDim = AngleDim
ghci> instance Dimension AngleDim where type DimFactorsOf AngleDim = '[]
Loading package transformers-0.3.0.0 ... linking ... done.
Loading package pretty-1.1.1.1 ... linking ... done.
Loading package array-0.5.0.0 ... linking ... done.
Loading package deepseq-1.3.0.2 ... linking ... done.
Loading package containers-0.5.5.1 ... linking ... done.
Loading package mtl-2.1.3.1 ... linking ... done.
Loading package multimap-1.2.1 ... linking ... done.
Loading package bytestring-0.10.4.0 ... linking ... done.
Loading package text-1.2.0.4 ... linking ... done.
Loading package parsec-3.1.8 ... linking ... done.
Loading package template-haskell ... linking ... done.
Loading package syb-0.4.4 ... linking ... done.
Loading package th-lift-0.7 ... linking ... done.
Loading package th-desugar-1.5 ... linking ... done.
Loading package singletons-1.1 ... linking ... done.
Loading package Boolean-0.2.3 ... linking ... done.
Loading package hashable-1.2.3.1 ... linking ... done.
Loading package nats-1 ... linking ... done.
Loading package unordered-containers-0.2.5.1 ... linking ... done.
Loading package semigroups-0.16.1 ... linking ... done.
Loading package void-0.7 ... linking ... done.
Loading package MemoTrie-0.6.2 ... linking ... done.
Loading package NumInstances-1.4 ... linking ... done.
Loading package vector-space-0.8.7 ... linking ... done.
Loading package units-2.2.1 ... linking ... done.
ghci> data Radian = Radian
ghci> type instance DefaultUnitOfDim AngleDim = Radian
ghci> :{
Prelude Data.Metrology Data.Metrology.SI Data.Metrology.Show| instance Unit Radian where
Prelude Data.Metrology Data.Metrology.SI Data.Metrology.Show|   type BaseUnit Radian = Canonical
Prelude Data.Metrology Data.Metrology.SI Data.Metrology.Show|   type DimOfUnit Radian = AngleDim
Prelude Data.Metrology Data.Metrology.SI Data.Metrology.Show|   type UnitFactorsOf Radian = '[]
Prelude Data.Metrology Data.Metrology.SI Data.Metrology.Show| :}
ghci> 0.4 % Radian
0.4

Now, if I define a Show instance, there's no problem:

ghci> instance Show Radian where show _ = "XXX"
ghci> 0.4 % Radian
0.4
DougBurke commented 9 years ago

I'm closing this as it was an IHaskell issue. Sorry for the noise.