2014-12-06 32 views
6

Bazen bu problemle karşılaşıyorum ve sonunda ortak bir çözüm ya da model olup olmadığını sormak istedim. İç içe geçmiş bir bağlam başvurusunda bir tür değişkeni bir dış bağlamdan tür yapmak mümkün mü? Örneğin,Haskell Bir Tür Değişkeni Referansı

foo :: a -> ... -> .. 
foo = ... 
    where bar :: a -> ... 

Şimdi bar 'ın a foo a farklıdır. Tipik olarak bu benim istediğim şey, ama bazen hayatı zorlaştırıyor ve onları aynı şekilde yapmaya ihtiyacım var. Geçmişte ikiyi birleştirmek için tip denetçisini zorlamak için kirli numaralar kullandım, ancak bazen engellenirim. İşte en son örneğim (Parsec işlevi) beni bu soruyu sormak için beni teşvik etti.

data Project = ... deriving Enum 
data Stuff = ... 

pProject :: Monad m => P m Stuff 
pProject = do 
    stuff <- pStuff 
    ... 
    convert stuff <$> pEnum :: P m Project 

pEnum :: (Monad m, Enum a) => String -> P m a 
pEnum = ... 

convert işlevi dolayısıyla ben ek açıklama :: P m Project belirtmek zorunda türü gerekli. Ancak, bu, m'u tanıtmam gerektiği anlamına geliyor, bu da maalesef aynı imzanın m işlev imzasıyla aynı değil. tip denetleyicisi raporları, bu şununla:

bağlamda Monad m

den pEnum bir kullanımından kaynaklanan Monad m1 anlamak Could işlev imzası en m bazı çirkin kesmek olmadan başvurmak için bir yol var mı? (Çirkin bir hack, çalıştırılamayacak, ancak yalnızca iki türü birleştirmek için var olan kukla kod ekliyor olurdu.)

cevap

13

Kapsamları kapsamaktan tür değişkenleri başvuruda bulunmanıza olanak veren ScopedTypeVariables uzantısını arıyorsunuz. Geriye doğru uyumluluk için

{-# LANGUAGE ScopedTypeVariables #-} 

, sadece açık bir forall sahip imzaları yazmak için de geçerlidir. Yani yazmak zorunda olacaktır: Bundan sonra

pProject :: forall m. Monad m => P m Stuff 

, sen pProject kapsamı içinde değişken doğru türe m başvurmak mümkün olurdu.

+5

'ScopedTypeVariables' yalnızca açık bir 'forall' olan imzalar için geçerli olduğuna dikkat ettiğiniz için teşekkür ederiz. Hiç şüphe yok ki neredeyse hiç işe yaramadı ... – Cirdec

+3

Bu tam olarak doğru değil - 'ScopedTypeVariables', forall 'olmadan bile sınıf bildirimlerinde belirtilen tip değişkenleri yapar. Bu nedenle, bir mahvolmuş Haskell 2010 programının anlamını değiştirebilir. – shachaf