2012-08-09 24 views
4

我試圖爲一個歸納數據類型(描述帶數據類型和模式匹配的lambda演算版本)創建一個靈活表示。這裏的靈活性應該意味着在節點上添加額外的數據(免費的comonad風格)或者替換(免費的monad風格)很容易。因此,這裏是我有:在實例上下文中需要泛型實例(對於更高版本類型的構造函數)

type Tie f φ = φ (f φ) 

type Id = String 
type Var = Id 
type Con = Id 

data Pat φ = PVar Var 
      | PCon Con [Tie Pat φ] 
      | PWildcard 

data Expr φ = EVar Var 
      | ECon Con 
      | EApp (Tie Expr φ) 
      | ELam (Tie Pat φ) (Tie Expr φ) 

麻煩的是當我想要得到的Show實例。當然,我可以做這樣的事情:

{-# LANGUAGE FlexibleContexts, UndecidableInstances #-} 
{-# LANGUAGE StandaloneDeriving #-} 

deriving instance (Show (φ (Pat φ))) => Show (Pat φ) 
deriving instance (Show (φ (Expr φ)), Show (φ (Pat φ))) => Show (Expr φ) 

但是,當歸納結構變得更加複雜時,用手寫出上下文變得笨拙。

理想情況下,我希望能夠寫類似

{-# LANGUAGE RankNTypes #-} 
deriving instance (forall a. Show (φ a)) => Show (Expr φ) 

以表達算符φ應該是,在某種意義上,「透明」,以顯示實例。

有沒有辦法做到這一點?

+0

我從來沒有在超類上下文中看到「forall」。 – 2012-08-09 07:19:46

+0

是的,因此這個問題... – Cactus 2012-08-09 11:12:39

回答

1

一種可能的解決方案將涉及

class Show1 f where 
    showsPrec1 :: Show a => Int -> f a -> ShowS 

這種類型的類在prelude-extras類似地定義。不幸的是,Haskell的派生機制不會利用它,因此不能使用。一個可能的替代可能是使用新的GHC.GenericsDefaultSignatures來創建,儘管不是「派生」,至少是微不足道的實例。

instance (Show1 φ) => Show (Pat φ) 
instance (Show1 φ) => Show (Expr φ) 

現在的困難部分:實際使用GHC.Generics。什麼可以用來爲

instance (Show1 f, Show a) => Show (f a) where showsPrec = showsPrec1 

然而,這需要OverlappingInstances(除其它問題)的極端不利。一種可能的解決方案是定義一個陰影類Show

class Show' a where showsPrec' ... 
instance (Show1 f, Show' a) => Show' (f a) where ... 

如果所有GHC.Generics機械已經到位(GShowGShow1,默認簽名等),那麼最終的結果不會顯得太恐怖了。

instance (Show1 φ) => Show' (Pat φ) 
instance (Show1 φ) => Show (Pat φ) where showsPrec = showsPrec' 
instance (Show1 φ) => Show' (Expr φ) 
instance (Show1 φ) => Show (Expr φ) where showsPrec = showsPrec' 

然而,假裝工作所需要的量並不壞(這是很糟糕),某些類型將不得不手動設置爲從showsPrec'轉發到showsPrecCharBool等) ,並且所有使用的類型都必須作爲Show'的實例,儘管如果GenericGeneric1的實例肯定不方便,但這些實例是微不足道的。

相關問題