2015-04-16 30 views
9

: Haskell'de unutkan tip eşanlamlı olması mümkün mü? Bunun gibi ben sadece bazen umurumda bir fantom parametresi olan bir tür varsa

data Foo p a b = Bar a b 

bir tür eş anlamlısı yazmak için herhangi kesmek yolu var Baz a b bazı p için Foo p a b edilir Baz şekilde mi ben unuttun mu?

type Baz a b = Foo p a b 

ve (uygun uzantılı) yapabilirsiniz ederken:

Sen yapamaz çünkü yapabilirim Böyle görünmüyor

type Baz a b = forall p.Foo p a b 

, ne istiyorum yapar türünde bir değeri Baz a b yazarak "rijit tip değişkeni" hakkında bir mesajla dönüştürmeyin.

Aşağıdaki gibi, bu etkiyi gerçekleştirmek için başka bir kontrollör katmanına mı ihtiyacınız var? Kısaca nedenini açıklar mısınız?

data Baz' a b = forall p.Baz' (Foo p a b) 
+0

Bence bu tür bir davranış arıyorsunuz (http://www.reddit.com/r/haskell/comments/32k1eu/new_in_ghc_710_partial_type_signatures/cqbxmra), ancak şu anda desteklenmiyor. – rampion

cevap

10

Bu, yazım eş anlamlı olarak yapılmasının bir yolu yoktur. Ancak, GHC 7.10'unuz varsa, PartialTypeSignatures uzantısını açabilir ve bunun yerine Foo _ a b yazabilirsiniz. GHC'den ayrıldığınız her bir delik hakkında sizi bu şekilde uyarmaması için -fno-warn-partial-type-signatures kullanın.

+0

Bunu bir çok durumda taze tip değişkenleri icat ederek yapabilirsiniz. Kısmi tip imzaların muhtemelen diğerini kapsadığı ve benzersiz isimler oluşturmanıza gerek kalmadan sizi koruduğu için iyi bir fikir. –

6

Bu, eş anlamlı yazımlarla gerçekten güvenilir bir şekilde yapılamıyor. Varoluşsal türlere veya sıra-n türlerine ihtiyacınız var. Sorun, Haskell'in tip eşanlamlılarının tamamen intersubstitutable olmasına izin vermesidir. Yani, type Baz a b = Foo p a b'u tanımladığınızda, Foo p a b'un bulunduğu her bağlamda, Baz a b'u kullanmanıza izin vermiş olursunuz ve bunun tersi de geçerlidir. Eğer bu tip bir işlevi olsaydı Yani, örneğin:

f1 :: Foo Something a b -> Whatever Something b a 

Sonra nedeniyle ikame edilebilirlik, bu aynı tip olurdu:

f1 :: Baz a b -> Whatever Something b a 

Ve bu şekilde:

f1 :: Foo p a b -> Whatever Something b a 
o zaman bu kadar uzmanlaşmak olabilir

...:

f1 :: Foo SomethingElse a b -> Whatever Something b a 

Peki, ne yapabilirsin? Eğer gidebiliriz

{-# LANGUAGE GADTs #-} 

data Baz a b where 
    Baz :: Foo p a b -> Baz a b 

İkinci yol: rütbe-n türleri ve devamı-pas stili:

aynı şeyi yapmanın

{-# LANGUAGE ExistentialTypes #-} 

data Baz a b = forall p. Baz (Foo p a b) 

Alternatif yol: Tek bir varoluş sarıcı türü tanımlamaktır

{-# LANGUAGE RankNTypes #-} 

-- To consume one of these, you pass a "callback" function to `runBaz`, 
-- which is not allowed to restrict the type variable `p`. 
newtype Baz a b = Baz { runBaz :: forall p r. (Foo p a b -> r) -> r } 

makeBaz :: Foo p a -> Baz a b 
makeBaz foo = Baz ($foo) 

Denemeye çalıştığınız ve (söylendiği gibi) çok iyi çalışmadığınız üçüncü yol: tür eş anlamlılar + müstehcen türler (tür argümanları olarak gerçekleşmesi için forall eş anlamlılarını almak gerekir) Çoğu durumda).