3

我有一些这样的类型:

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)

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

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

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

编辑:另外,一种让它推断 in Money athe ais的Typeable方法会很好,所以我不需要在(Typeable a) =>任何地方添加。不过那是次要的。

4

2 回答 2

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本身不需要。
  • 这似乎破坏了Show为 GADT 自动推导的能力。
于 2015-02-07T23:52:05.540 回答
1

如果您正在跟踪需要 Typeable 的旧文档,您可能不需要它。从 ghc 8.2 开始,对 Typeable 的显式调用已被弃用,并包含“课程标准”;所以不需要语言编译指示等。

于 2021-08-18T22:31:59.843 回答