如何为 DataKinds 派生类型自动派生 Typeable 实例?
How can I automatically derive Typeable instance for DataKinds derived types?
我有一些这样的类型:
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
的能力。
如果您正在跟踪需要 Typeable 的旧文档,则您可能不需要它。从 ghc 8.2 开始,对 Typeable 的显式调用已被弃用并包含在“par for the course”中;所以不需要语言 pragma 等。
我有一些这样的类型:
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
的能力。
如果您正在跟踪需要 Typeable 的旧文档,则您可能不需要它。从 ghc 8.2 开始,对 Typeable 的显式调用已被弃用并包含在“par for the course”中;所以不需要语言 pragma 等。