2015-02-07 118 views
3

我有一些类型是这样的:如何自动派生DataKinds派生类型的Typeable实例?

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) =>无处不在。虽然这很小。

回答

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 [email protected](Money _) = M.lookup (typeOf a) 

但是请注意:

  • 通过GADTs的性质,这实际上需要评估a以获取Typeable环境,而其中typeOf本身没有。
  • 这似乎破坏了为GADT自动派生Show的能力。
+1

谢谢。有没有关于AutoDeriveTypeable的文档,除此之外(http://hauptwerk.blogspot.com/2012/11/coming-soon-in-ghc-head-poly-kinded.html)?它确实解决了样板问题(尽管由于某种原因,我仍然需要'Money'上的类型化派生)。 至于把Typeable约束放在'Money'上,我早些时候和现在就尝试过,并且它不会让findRate推断出这一点。对你起作用吗? – 2015-02-08 00:03:22

+1

@RamithJayatilleka [官方GHC文档](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/deriving.html#auto-derive-typeable)在那里,但这只是一个段落。哦,我*不需要'Money'上的'Typeable',这与GHC 7.8.3一样。请注意,我如何稍微更改了'findRate'的代码;与“Money _”匹配的模式就是将Typeable实例带入范围。 – 2015-02-08 00:17:57

+0

哦,我明白了。这更有意义。不幸的是,这对我来说更糟,因为我不能这样做'undefined :: Money a'。我必须做'Money(undefined :: a)'而不是(或者甚至可以工作?),而且我宁愿只放置Typeable约束。我认为。 – 2015-02-08 00:35:25