2014-06-30 20 views
6

varsayalım böyle bir veri tipi vardır:Şartlı tür kurucusu üzerinde varoluşsal türü için parametreli göster türetmek

{-# LANGUAGE RankNTypes #-} 
data X a = forall b. Show b => X (a b) 

Ben Show (X a) türetmek istiyorum, ama tabii bu yüzden bir örneği varsa bunu yalnızca yapabilirsiniz Show (a b). Ben

{-# LANGUAGE StandaloneDeriving #-} 
deriving instance Show (a b) => Show (X a) 

yazmak için cazip ama o forall bağlı olduğundan maalesef tipi değişken b örnek bağlamında kullanılamaz.

Benim sonraki girişimi şöyle, veri tipi tanımı forall içine Show (a b) bağlamı taşımak oldu:

data X a = forall b. Show (a b) => X (a b) 
deriving instance Show (X a) 

Bu derler, ama ne yazık ki şimdi bir bir X inşa yeteneğini kaybetmiş göze çarpmayan (a b).

X herhangi (a b) inşa ve daha sonra şartlı (a b) showable olup Show (X a) yalnızca türetmek izin vermek için herhangi bir yolu var mı?

cevap

7

Bu, Prelüd sınıflarında bir eksikliktir. prelude-extras paketinde yapılandırılmış olsa da, bunun için güzel bir yol var. Aşağıda özetleyeceğim.

Daha yüksek kaliteli Show sınıfı oluşturmak istiyoruz. Bu

deriving instance Show1 a => Show (X a) 

Maalesef derleyici Henüz bu türetme ulaşmak için yeterli bilgiye sahip değil gibi Sonra, en azından doğru bizim istenen kısıtlamayı ifade edebilir bu

class Show1 a where 
    show1 :: Show b => a b -> String 

benziyor. Show (a b)'u türetmek için (Show b, Show1 a)'un yeterli olduğunu göstermemiz gerekiyor. Bunu yapmak için bazı (korkunç, ama sanely-kullanılan) uzantıları

{-# LANGUAGE FlexibleInstances   #-} 
{-# LANGUAGE OverlappingInstances  #-} 

instance (Show b, Show1 a) => Show (a b) where 
    show = show1 

Ve etkinleştirmeniz gerekir şimdi derleyici ihtiyacımız olan şey türetmek mümkün olacak kanıtı kabul ettiklerini

data X a = forall b . Show b => X (a b) 
deriving instance Show1 a => Show (X a) 
+0

Çok kötü. GHC kılavuzunun OverlappingInstances hakkında söylediği her şey korkutucu. – Will

+0

Evet, bu kesinlikle tavsiye edilmez. Show1, diğer örnekleri kolayca kolayca gizleyebilir. –

5

J. Abrahamson'un cevabına benzer ama biraz farklı bir yaklaşım alırdım.

Kesinlikle ne tür sınıfları gerekir çünkü sen yapılamaz sormak statikçözülecek fakat Show (a b) varlığı b ait instantation bağlı dinamik olabilir. Bu örnekleme, X değerinin içinde gizlidir ve bu nedenle bilinmeyen bir X b dışında hiçbir şeyiniz olmadığında tür denetleyicisine görünmez. biz zaten Show b hep doğru olduğunu bildiğimiz sonra Show (a b) varlığı aslında b bağımlı olmadığı için Show b, yaptığında

O Show (a b) gibi a üzerinde bir koşul yazmak için iyi olurdu var.

Biz doğrudan bu şartı yazamazsınız, ama biz GADTs kullanarak buna benzer bir şey ifade edebilir:

ShowDict a tip Show a sınıfın şeyleşme bir tür sağlar
{-# LANGUAGE GADTs #-} 
data ShowDict a where 
    ShowDict :: Show a => ShowDict a 

- biz etrafında geçebilir bir şey var ve işlevleri tanımlayın. Biz Show b var her

Özellikle şimdi durumun Show (a b) ifade eden bir Show1 sınıf tanımlayabilirsiniz:

class Show1 a where 
    show1Dict :: ShowDict b -> ShowDict (a b) 

Ve şimdi ShowDict (a b) ve sonra desen eşleştirme oluşturarak Show1, açısından Show (X a) tanımlayabilirsiniz

{-# LANGUAGE ScopedTypeVariables #-} 
instance Show1 a => Show (X a) where 
    show (X (v :: a b)) = 
     case show1Dict ShowDict :: ShowDict (a b) of 
      ShowDict -> "X (" ++ show v ++ ")" 

daha tam uygulanması da inc olacaktır: üzerinde Show örneğini ortaya çıkarmak için Show'un diğer üyelerini (showsPrec ve showList) çevirin.

Bu çözüm hakkında güzel bir şey kolayca otomatik yatan Show örneğini yeniden, [] için Show1 tanımlayabilirsiniz olmasıdır:

instance Show1 [] where 
    show1Dict ShowDict = ShowDict 
Ben de J. Abrahamson cevabı çok jenerik Show (a b) örneğini kaçınmayı tercih

, fakat mantığı örneğindeki örneğine koymak zorunda kalmanın olumsuz tarafı, kurucunun otomatik türetilmiş davranışını elde etmek yerine el ile uygulamak zorunda kalmamızdır.

+0

Genel olarak bu cevaba katılıyorum, ancak bu çözümlerin türetmeyi yitirdiğine dikkat etmek gerekir. Yine de, muhtemelen sadece kaçınılmaz bir sonuçtur. Türetme ve varoluşçular çok sık oynamıyorlar. –

+0

Aslında 'Göster' örneğinde 'X' yapıcısını görüntülemeyi unutmuştum, bu da cevabınızın önemli bir yanıdır. Ancak, evet, varoluşçu üzerine türetmek sıklıkla mümkün olmayabilir. –