2011-07-19 24 views
9

vardır: bu tek bir parametre ile tipleri için örneklerini oluşturmak için yeterli kolaydırTipi sınıf örneklerini tip sınıf şu tip sınıfı düşünün tek

class Listable a where 
    asList :: a t -> [t] 

:

instance Listable [] where 
    asList = id 

instance Listable Maybe where 
    asList (Just x) = [x] 
    asList Nothing = [] 

İki özdeş tip parametresi olan bir çift için nasıl örnek oluşturabilirim?

data V2 a = V2 a a 

v2 (p,q) = V2 p q 

instance Listable V2 where 
    asList (V2 p q) = [p,q] 

Şimdi asList $ v2 (47, 11) gibi şeyler yazabilirim, ama yenilgilerden bu tür amacı: Tabi ki bazı sarma yapabilirdi.

Her iki tip parametresinin eşit olduğu durumlara çift türünü sınırlamanın ve bunun için Listable örneğini yazmanın bir yolu var mı? Değilse, olağan geçici çözüm nedir?

cevap

13

. Ne yazık ki, çoğu aslında çalışmıyor. Heyhat!

instance Listable (\a -> (a, a)) where 
    asList (p, q) = [p,q] 

Maalesef tip düzey lambda'lar almıyorlar:

Birincisi, fonksiyonel programcı olarak, ben bu gerçekten yazmak istiyorum olduğuna bahse girerim. tip eşanlamlı tam olarak uygulanan olmadığı için, ya izin verilmez

type Same2 f a = f a a 

instance Listable (Same2 (,)) where { ... } 

: Bir tür eşanlamlı kullanarak yukarıdaki lambda adlandırılmış versiyonunu yazabiliriz. tutarlı, tek bir tür için yok çünkü, bu da başarısız olsa app ne olabileceğini düşünmeden

class Listable app f where 
    asList :: app f a -> [a] 

instance Listable __ Maybe where { ... } 

instance Listable __ (,) where { ... } 

: Biz yerine türü değişkenleri nasıl uygulanacağını tarif edersiniz ekstra argüman alarak tipi sınıfını düşünebiliriz f parametresi.

Aslında işe yarayan şeylere geçerken, en yaygın yol, eş anlamlılık yaklaşımını newtype içine sarmak olduğunu düşünüyorum, daha sonra yalnızca içerdiği sarma ve paketlemeyle uğraşmaktır.

newtype Same2 f a = Same2 (f a a) 

instance Listable (Same2 (,)) where { ... } 

Biraz çirkin ise uygulanabilir. Ayrıca, bu tür yapıcı bileşimi ve diğer oyuncakları da tanımlayabilir, daha sonra çember atlama noktaları olan bir kiriş yığını altına gömülmüş tip-seviye nokta-içermeyen ifadelerle delirebilirsiniz. Son bir yaklaşım olarak

, ayrıca tam uygulanmış versiyonu tek tip parametresi için den gidiyor, "tersten" yukarıdaki lambda tarzı bir yaklaşım kodlayabilir:

class Listable t where 
    type ListableElem t :: * 
    asList :: t -> [ListableElem t] 

Olmak Böyle bir şey yapabilen tip aileler için ana motivasyonlardan biridir. Aynı şey MPTC ve fundeps ile ifade edilebilir, ancak 1) eşdeğer ve 2) çok daha çirkin, bu yüzden bunu yazmaya çalışmam.

+0

Bunu denemek için tembel olmaktan dolayı özür dilerim, ama son yaklaşım "Listable (a, a)' ye izin vermez - değil mi? – yatima2975

+0

@ yatima2975: En dıştaki tip kurucu olarak '(,)' ile farklı örneklere sahip olma pahasına, evet. Muhtemelen cevabımın bir örneği olarak şunu söylemeliydim, şimdi bahsettiğine göre ... –

2

Bunu yapmak için bazı sarmalayıcı türlerini tanımlamanız gerekir. (Bununla birlikte newtype kullanmalıdır.) Hatta tanımlayabilirsiniz: kavramsal Bunu yapmak için birçok yol vardır

newtype Foo t a = Foo(t a a) 

instance Listable (Foo (,)) where 
    asList (Foo (a,b)) = [a,b]