2015-02-07 167 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