2010-10-18 112 views
5

最近我一直在玩RankNTypes,想知道是否有可能在實例聲明中使用它們 。RankNTypes爲實例聲明?

下面是使用開放式數據類型

data (Expr a, Expr b) => Add a b = Add a b deriving(Show)       

instance (Expr a, Expr b) => Expr (Add a b) 

instance (Evaluation a, Evaluation b) => Evaluation (Add a b) where 
    eval (Add x y) = eval x + eval y 

這裏我寫這樣的限制(評價A,B評價)一個簡單的例子,但基本上我只想寫類似(FORALL一個。評價一個)。這甚至有可能嗎?

問候, raichoo

回答

4

(forall a . Evaluation a)並沒有真正意義:這將意味着,每一個類型(包括任何未來類型的人可能使)是的Evaluation一個實例。

此外,在這種情況下,我認爲你的代碼列出你想要的Evaluation的實例是正確的;不要求比你實際需要的更多。

但是肯定會出現這樣的情況,即能夠按照您描述的方式對班級約束進行量化,而且不可能直接進行。一個例子是,你可能想從Monoid自動進行MonadPlus實例(使用包裝類型以避免OverlappingInstances問題):

newtype MonoidWrapper m a = MonoidWrapper { unMonoidWrapper :: m a } 

instance Monad m => Monad (MonoidWrapper m) where ... 

instance (Monad m, forall a . Monoid (m a)) => MonadPlus (MonoidWrapper m) where 
    mzero = MonoidWrapper mempty 
    mplus (MonoidWrapper a) (MonoidWrapper b) = MonoidWrapper (mappend a b) 

你不能寫這篇文章,但使用GADTs或存在的類型,你可以模擬它,帶有一些句法痛苦:

data MonoidDict a where 
    MonoidDict :: Monoid a => MonoidDict a 

class AlwaysMonoid m where 
    alwaysMonoidDict :: MonoidDict (m a) -- note the implicit forall a here 

instance Monad m => Monad (MonoidWrapper m) 

instance (Monad m, AlwaysMonoid m) => MonadPlus (MonoidWrapper m) where 
    mzero = mymzero 
    where 
     -- needed to give name to 'a' for ScopedTypeVariables 
     mymzero :: forall a . MonoidWrapper m a 
     mymzero = case (alwaysMonoidDict :: MonoidDict (m a)) of 
        MonoidDict -> MonoidWrapper mempty 
    mplus = mymplus 
    where 
     mymplus :: forall a . MonoidWrapper m a 
       -> MonoidWrapper m a -> MonoidWrapper m a 
     mymplus (MonoidWrapper a) (MonoidWrapper b) 
     = case (alwaysMonoidDict :: MonoidDict (m a)) of 
      MonoidDict -> MonoidWrapper (mappend a b) 
+0

謝謝,我會玩這個:) – raichoo 2010-10-28 08:34:31