我有一些像这样的类型:

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 aaTypeable的方法将是不错的,因此,我不需要到处添加(Typeable a) =>。不过那是次要的。

最佳答案

是的,您可以使用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本身不需要。
这似乎破坏了GADT自动导出Show的能力。

10-06 02:43