如何自动为DataKinds派生类型派生Typeable实例?

时间:2015-02-07 23:29:12

标签: haskell types deriving data-kinds

我有类似这样的类型:

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

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

我想在这个函数中使用typeOf

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

这不起作用,因为findRate中的a类型没有Typeable个实例。所以我通过这样做来修复它:

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

然而,当货币数量增加时,这成为很多样板。有没有办法指定所有类型的Currency类型应该派生Typeable个实例?

编辑:另外,一种方法可以推断Money a中的a Typeable会很好,所以我不需要添加{{1}无处不在。这虽然是次要的。

1 个答案:

答案 0 :(得分:4)

是的,您可以使用AutoDeriveTypeable扩展程序。

对于另一部分,我能想到的最接近的事情是将Typeable c =>置于GADT定义中,如下所示:

{-# 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)

请注意:

  • 根据GADT的性质,这需要实际评估a以获取Typeable上下文,typeOf本身不会。{/ li>
  • 这似乎破坏了为GADT自动派生Show的能力。