我有类似这样的类型:
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}无处不在。这虽然是次要的。
答案 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)
请注意:
a
以获取Typeable
上下文,typeOf
本身不会。{/ li>
Show
的能力。