我有一些像这样的类型:
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
的方法将是不错的,因此,我不需要到处添加(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
的能力。