2017-11-08 99 views
9

düzeltir.bu kodu düşünün bir tür hatasının

Foo.hs:16:17: 
    Could not deduce (Foo a) arising from a use of ‘bar’ 
    from the context (SomeClass a) 
     bound by the type signature for foo :: SomeClass a => a -> Int 
     at Foo.hs:15:8-32 
    Possible fix: 
     add (Foo a) to the context of 
     the inferred type of x :: Int 
     or the type signature for foo :: SomeClass a => a -> Int 
    In the expression: bar t 
    In an equation for ‘x’: x = bar t 
    In the expression: let x = bar t in x 

Bunu düzeltmek için iki yol vardır: Bunun yerine, GHC o kadar Foo a => SomeClass a örneğini kullanarak yapmanız gerekir varsayar foo yılında

  1. , bar t
  2. için let x = bar t in x değişen çizgisini instance SomeClass Int ekleme benim program

Burada neler oluyor? Bu sorun neden ortaya çıkıyor ve bu düzeltmeler neden çalışıyor?


Bu örnek, elbette, asıl sorunum tarafından basitleştirilmiştir. Çok dilli dönüşüm için Cubix çerçevesindeki çalışma sırasında karşılaştım (arxiv.org/pdf/1707.04600).

Asıl sorunum, InjF f IdentL FunctionExpL kısıtlamasına sahip bir işlevi içerir ("f, işlev çağrısında işlevi belirtmek için tanımlayıcıların kullanılabileceği bir dildir"). Ben bir (Could not deduce FunctionIdent :<: f hatası) bana yanlış veren bir (overlappable) örneği (FunctionIdent :<: f) => InjF f IdentL FunctionExpL var.

orada belirli Foo için kapsamındaki bir örnek InjF Foo IdentL FunctionExpL, yani bu diğer örneği sorunu çözmek gerektiğini öngörür leftaroundabout cevabı, tam hikaye olmasa bile bu sorun devam.

+2

'{- # OVERLAPPABLE # -}' ve '{- # LANGUAGE FlexibleContexts # -}' hiçbir şeyi etkilemez. Derlemenin başka bir yolu: 'let' bağlanmasına bir' x :: Int 'ekleyin. – Alec

+1

Belki de en iğrenç şey, modülde allo'da bir _no örneği olduğunda da yazım denetimi yapmasıdır ... – leftaroundabout

cevap

3

Bunun nedeni, derleyicinin mümkün olduğunca genel olarak x yapmasını sağlamasıdır: (SomeClass a) => Int olmasını ister (bunu kendiniz yazdıysanız belirsiz bir tür olur). Bu tür bir garip yerel türü önlemenin bir yolu -XMonoLocalBinds'u etkinleştirmektir, ancak bunu gerçekten tavsiye etmem.

Şimdi, derleyici yazım denetimine devam ediyor. Bu noktada, tam olarak bir instance SomeClass, yani tüm (Foo a) => SomeClass a tüm yakalama yok, bu nedenle hiçbir belirsizlik yok. (Prensip olarak, Haskell örnek çözünürlükte belirsizliği tamamen ortadan kaldırır; OVERLAPPABLE bunu değiştirir ancak ek bir instance SomeClass Int olduğu zaman olduğu gibi sadece bir ihtiyaç olduğunda harekete geçer.) Bu nedenle derleyici bu örneğe derhal bildirir ve böylece 'u ortadan kaldırır. c'un tip kontrolü. Bunu yapmak, bir örneğin kısıtlaması ile değiştirilmesi gereken bir sınıf kısıtlaması istediğiniz durumlar için gereklidir. Bu, belirtilen örnekte yararsız görünebilir, ama bunu Bir üst olarak ifade edilemez çünkü çok daha makul kodunuzda daha formda

instance Bar a => SomeClass (Maybe a) 

... örneklerini olduğunda aslında çok önemli olduğunu kısıtlama ve herhangi bir çakışma olmadan mükemmel tamam. Derleyici, bu durumlarda Bar a'a kadar olan kısıtlamayı azaltmadığı takdirde, Maybe türünü asla çözemez.

Sonuç: çakışan örneklerden kaçının; mümkünse, süper-sınıf bildirimleriyle sınıf ilişkilerini ifade edin, ya da bir GADT'deki kısıtlamaları yeniden tanımlayın (bu garip olan, ancak hangi kısıtlamanın kullanılacağı konusunda tam kontrol sağladığınız).

+0

1) Ne demek (Foo a => SomeClass a) kapsamdaki tek örnek? Beyannamede (SomeClass a) kısıtlaması nedir? –

+0

2) Neden basitleştirmek için SomeClass (Belki a) kısıtlamasını basitleştirmek gerekiyor? Neden bu karar verme adımını, zaten bildirilen içeriğe baktıktan sonra sonuna kadar ertelemez? –

+0

3) Bu, verdiğim basitleştirilmiş örneği açıklamaya yardımcı olur, ancak gerçek örnek için yetersiz kalmaktadır. Gönderiyi de gerçek örnek vermek için düzenleyeceğim. –