Home > Blockchain >  "Inheriting" operations in haskell data types
"Inheriting" operations in haskell data types

Time:08-17

I have created the following type:

data Inch = Inch Double
instance Show Inch where
    show (Inch i) = show i    " inches"

Now, I'd like to be able to perform some mathematical operations on this type and, since the type itself is basically just a synonym with Double I was expecting to get them for free. However, this is not the case:

ghci> (3 :: Double) / 2
1.5
ghci> (3 :: Inch) / 2

<interactive>:74:2: error:
    • No instance for (Num Inch) arising from the literal ‘3’
    • In the first argument of ‘(/)’, namely ‘(3 :: Inch)’
      In the expression: (3 :: Inch) / 2
      In an equation for ‘it’: it = (3 :: Inch) / 2

<interactive>:74:13: error:
    • No instance for (Fractional Inch) arising from a use of ‘/’
    • In the expression: (3 :: Inch) / 2
      In an equation for ‘it’: it = (3 :: Inch) / 2

I think I can solve this by defining:

(/) :: Inch -> Double -> Inch
(Inch i) / n = Inch (i GHC.Real./ n)

This allows the previous code to run fine:

ghci> (Inch 3) / 2
1.5 inches

But I feel it's cumbersome and can't help thinking there surely must be a better way. Is there?

CodePudding user response:

I would recommend this:

{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}

import GHC.Generics
import Data.VectorSpace

data Length = Inches Double
  deriving (Generic, Show, AdditiveGroup, VectorSpace)

Then

ghci> Inches 3 ^/ 2
Inches 1.5

I'm using the ^/ operator from the vector-space package because that actually has the suitable type v -> Scalar v -> v. By contrast, the standard / from the Fractional class has simply type v -> v -> v, which would be Length -> Length -> Length in this case, which does not make sense physically.

  • Related