2017-06-24 22 views
6

Identity için monad trafo türünü tanımlarsam, Show örneğini türetebilir.Neden Show örneği, BelkiT için türetilemiyor?

newtype IdentityT f a = 
    IdentityT { runIdentityT :: f a } 
    deriving (Show) 

instance Show (f a) => Show (IdentityT f a) 

elde edecek Ama Maybe

newtype MaybeT m a = 
    MaybeT { runMaybeT :: m (Maybe a) } 
    deriving (Show) 

için monad trafo türünü tanımlamak eğer

• No instance for (Show (m (Maybe a))) 
     arising from the first field of ‘MaybeT’ (type ‘m (Maybe a)’) 

yana hatayı olsun 0 Show örneği vardır, işe ve türetmek beklenir

instance Show (m (Maybe a)) => Show (MaybeT m a) 

Neden olamaz?

cevap

3

GHC, bir örneğin arama sonlandırmayı garanti edip etmediğini belirlemek için bir sezgisel yöntem kullanır. Buradaki sonlandırma ile, bir örnek ararken sonsuza dek döngü yapmayacağımız anlamına gelir. Somut olarak, bu

instance Show a => Show a where ... 

olarak yasak gereken bu

instance Show [a] => Show a where ... 
GHC kabaca, örneğin içerik ( => önceki bölüm) kısıtlamaları "küçük" olarak kısıtlamadan daha olmalıdır gerektirir

kafa (=>'dan sonra). Yani, bu kabul eder: a beri

instance Show a => Show [a] where ... 

[a] fazla türü yapıcı az içerir.

Ayrıca bu kabul eder: f aIdentityT f a fazla türü yapıcısı az bulunur

instance Show (f a) => Show (IdentityT f a) where ... 

beri.

Ancak

instance Show (f (Maybe a)) => Show (MaybeT f a) where ... 

yapıcıları aynı sayıda kullanır! Bu nedenle, bir döngüye neden olmayacağından emin olmak kabul edilmez. Sonuçta, daha sonra, biz

instance Show (MaybeT f a)) => Show (f (Maybe a)) where ... 

karşılamak olabilir ve bu iki durumdan en az bir fesih garanti etmek reddedilmesi gerektiği ortadadır.GHC, her ikisini de reddetmeyi seçiyor. Bu kısıtlamayı rahatlatır

UndecidableInstances. GHC her iki örneği de kabul edecek ve şimdi de döngülerden kaçınmak için yük bize geliyor.

5

Bence bir çıkmaz sokağa kadar biz (ben 8.2.1 kullanıyorum) ghc önerilerini izleyerek sorunu görebilirsiniz düşünüyorum:

Prelude> :{ 
Prelude| newtype MaybeT m a = 
Prelude| MaybeT { runMaybeT :: m (Maybe a) } 
Prelude| deriving (Show) 
Prelude| :} 

<interactive>:12:13: error: 
    • No instance for (Show (m (Maybe a))) 
     arising from the first field of ‘MaybeT’ (type ‘m (Maybe a)’) 
     Possible fix: 
     use a standalone 'deriving instance' declaration, 
      so you can specify the instance context yourself 
    • When deriving the instance for (Show (MaybeT m a)) 
Prelude> :set -XStandaloneDeriving 
Prelude> deriving instance Show (m (Maybe a)) => Show (MaybeT m a) 

<interactive>:17:19: error: 
    • The constraint ‘Show (m (Maybe a))’ 
     is no smaller than the instance head 
     (Use UndecidableInstances to permit this) 
    • In the stand-alone deriving instance for 
     ‘Show (m (Maybe a)) => Show (MaybeT m a)’ 

Tamam, Show çünkü derive için MaybeT olası değildi Bu kısıtlamaya izin verilmediğinden, typechecker'ın feshedilemeyeceği bir tür kısıtlama olduğu için. Bu örnekte "örnek başlığından daha küçük olmayan" ifadesinin ne anlama geldiği hakkında daha fazlasını okuyabilirsiniz: https://stackoverflow.com/a/17866970/176841

+1

Ancak ikinci önerisi, "UndecidableInstances" işlevini etkinleştirmek için gayet iyi. – dfeuer

+0

Bu yüzden benim için örneği türetmek için derleyiciyi almak için 'UndecidableInstances' kullanabilirim, ancak' MaybeT' türü 'IdentityT' türünü ele alabildiği halde türetmeden bunu türetemez hale getirir? Ör. Ben herhangi bir uzantı olmadan BelkiT [Sadece 1] 'göstermek mümkün olacağını umuyordum – robertjlooby