Ramith Jayatilleka
Ramith Jayatilleka

Reputation: 2152

How can I automatically derive Typeable instance for DataKinds derived types?

I had some types like this:

data Currency = USD | EUR
              deriving (Show, Typeable)

data Money :: Currency -> * where
  Money :: Int -> Money c
  deriving (Show, Typeable)

And I wanted to use typeOf with them in this function:

findRate :: Money a -> Rates -> Maybe Double
findRate a = M.lookup (typeOf a)

That didn't work, because the type a in findRate didn't have a Typeable instance. So I fixed it by doing this:

deriving instance Typeable USD
deriving instance Typeable EUR
findRate :: (Typeable a) => Money a -> Rates -> Maybe Double

However, that becomes a lot of boilerplate when the number of currencies increase. Is there a way to specify that all types of kind Currency should derive a Typeable instance?

EDIT: Also, a way to make it infer that in Money a the a is Typeable would be nice, so then I don't need to add (Typeable a) => everywhere. That's minor though.

Upvotes: 3

Views: 663

Answers (2)

Edmund's Echo
Edmund's Echo

Reputation: 908

If you're tracking an older document that requires Typeable, you likely do not need it. As of ghc 8.2, the explicit call for Typeable is deprecated and included "par for the course"; so no language pragma etc. is required.

Upvotes: 1

Ørjan Johansen
Ørjan Johansen

Reputation: 18189

Yes, you can use the AutoDeriveTypeable extension.

For the other part, the closest thing I could think of was to put Typeable c => inside the GADT definition as follows:

{-# LANGUAGE AutoDeriveTypeable #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}

import Data.Typeable
import qualified Data.Map as M

type Rates = M.Map TypeRep Double

data Currency = USD | EUR
              deriving (Show, Typeable)

data Money :: Currency -> * where
  Money :: Typeable c => Int -> Money c

instance Show (Money c) where
    show (Money n) = "Money " ++ show n

findRate :: Money a -> Rates -> Maybe Double
findRate a@(Money _) = M.lookup (typeOf a)

Note though:

  • By the nature of GADTs, this requires actually evaluating a to get the Typeable context out of it, which typeOf itself doesn't.
  • This seems to ruin the ability to derive Show automatically for the GADT.

Upvotes: 4

Related Questions