2011-07-20 14 views
6

Bir monad örneğini, M kapsayıcısı olarak M ile birlikte ve Show sınıfının üyesi olması gereken a türüyle tanımlamak istiyorum. Bu kısıtlama (a'un Show üyesidir), tip sistem tarafından sağlanmalıdır.Typeclass Show'da "a" olan bir Monad örneği "a" nasıl tanımlanır?

ben o böyle bir deneyin verdi ama M sağ Kind maalesef değil:

data M = forall a. Show a => M a 

instance Monad M where 
return x = M x 

Diğer tüm girişimleri Bunu başarmak için, aşağıdaki sorun çıkıyor: Monad bir yapıcı sınıfı olduğundan, İçerilen öğenin/elemanların a tipine açık erişimi yoktur, bu yüzden kısıtlayamıyorum.

Yeni bir Monad sınıfını tanımlamadan, buna bir çözüm bilen var mı?

cevap

7

Eh, GADTs kullanarak, bir anlamda bir tür kurucusu parametrelerini kısıtlamak aslında mümkündür:

data M a where 
    M :: (Show a) => a -> M a 

Ne yazık ki bu aslında burada yardımcı olmaz. Bir bakıma aslında bir şeyleri daha da kötüleştirir, çünkü bir kısıtlama olmaksızın bir Monad örneğine sahip olmak yerine, örneği yazmak imkansız hale gelir. Yukarıdaki yapıcı tipi imza bakarsak

, açıkça ne yaptığını temelde imkansız neden gösteriyor --which return benzer. Dönüş türü: (Monad m) => a -> m a, ve her zaman bağlanmayan tür değişkenler en dış düzeyde dolaylı olarak evrensel olarak belirlendiği için, "a tüm olası türleri için ve tüm olası türleri Monad, bir değer verildiği gibi olanları okuyabilir. a türünde m a türünde bir değer oluşturabilirsiniz ". "Herkes için" ifadesi oldukça basittir - dönüş türü sadece bir tip değişkeni kullanmakla kalmaz, aktif olarak a türüne izin verilmelidir.

Kısacası, hayır. İstediğinizi yapmanın bir yolu yoktur, çünkü standart Monad sınıfı standardı, karşıdaki değerini açıkça belirtir.

2

Hayır. Açıklanması kolay olmasına rağmen bu mümkün değildir. senin monad herhangi bir içerik türlerini kabul etmelidir, böylece

return :: Monad m => a -> m a 

imza değiştiremezsiniz: return tipi imzası göz at. Tür sınıfının kendisi içerik türünden bahsetmediğinden, üzerinde kısıtlamaların uygulanmasının bir yolu yoktur.

Yapmanız gereken tek şey, bu kısıtlamayı ihtiyaç duyulan tüm işlevler üzerine yazmak ve genel kısıtlamayı bırakmaktır. Sistemin sağlamlığı, yalnızca ihtiyaç olduğunda Show kısıtının varlığını kanıtlayabilirseniz hala garanti edilir.

+0

'Tür eşleşme: 'Monad'ın ilk argümanı' * -> * 'olmalıdır, fakat' M a 'türünde' * '' –

+0

@camccann Üzgünüz. Hayır, sorumu anlıyorum. Benimkilere benzeyen güncellenmiş cevabımı görün. – fuz

+0

Downvoter kendisi açıklayabilir misiniz? – fuz

1

Bu, bazı aşırı hile ile mümkündür. Bir uygulama için rmonad paketine bakın. Ancak, muhtemelen buna değmez.

Neden a'un Show olduğunu kısıtlamanız gerekir? Göster sınırını bu noktada zorlamak daha kolay olurdu, o zaman gerektiğinde doğal olarak yayılacak.

+0

Soru, "yeni bir" Monad "sınıfını tanımlamadan" belirtildi. Çeşitli yaklaşımlar elde etmek için çeşitli derecelerde hileler vardır, ancak hiçbiri standart Monad'ın etrafına sarılabilir. Her ne kadar RMonad muhtemelen 'AsMonad' sargısı için mümkün olan en az imtiyazın yapılmasına en yakın gelse de. –

+0

@camccann: 'AsMonad' standart Monad' sınıfı ile kullanılabilir. –

+0

Evet, ancak bunu yapmak (açıkçası), RMonad'ın kısıtlamalarını yok sayar; AsMonad'ın tek başına kullanmanız, doğrudan bir 'Monad' örneğiyle doğrudan yapamayacağınız bir şey vermez. Bunun yararı, sarma/açma işleminin ekstra bilgi depolaması ve böylece normal "Monad" işlevlerini kullanarak işlevler arasında dolaşırken mümkün olduğu kadar RMonad'ın özelliklerini koruyabilmenizdir. –

5

Tam olarak ne istediğinizi yapamayabilirsiniz, ancak başka bir olasılık, belirli bir olasılıkla, Show ile yapmayı düşündüğünüz her şeyi açıkça yapan bir eylem sağlamaktır. ,

report :: Show a => M a -> M a 

Ben Show ile bu modelin iyi bir kullanım başımın üst kapalı düşünemiyorum:

data M a = {- ... -} 
instance Monad M where -- notice: no Show constraint 
    {- ... -} 

Sonra ilaveten bazı eylemi kaynağı olabilir: Yani, siz varsayarak, olduğu ama ben bir Ord kısıtlaması için isteyebileceğiniz benzer bir örnek biliyorum. Kurulum, nondeterministic olan ([a] gibi) bir monad yapmak istediğiniz, ancak kopyaların (Set a gibi) bulunmadığıdır. Yinelenenleri kaldırmak için Eq veya Ord gibi bazı içerikler gerekir, ancak her return/>>= işleminde bunu talep edemeyiz. Bazı v1 çiftleşmesi ve v2 olsalar bile,

valuesOfInterest = collapse $ do 
    v1 <- allValues 
    v2 <- allValues 
    doSomethingInteresting v1 v2 

Ardından:

newtype Setlike a = Setlike { toList :: [a] } 
instance Monad Setlike where 
    return x = Setlike [x] 
    Setlike xs >>= f = [y | x <- xs, let Setlike ys = f x, y <- ys] 

collapse :: Ord a => Setlike a -> Setlike a 
collapse = Setlike . Data.Set.toList . Data.Set.fromList . toList 

Bu yüzden gibi kullanılabilir: Bunun yerine biz kullanıcı açıkça çiftleri birleşecek gerektiğini noktalarını işaretleyin talep Aynı ilgi değeriyle sonuçlanır, bu değer sonuçta sadece bir kez görünecektir.

Kullanım durumunuz için benzer bir hile de mümkündür.

İlgili konular