2017-06-16 6 views
2

I definiert eine einfache Liste Typ:`Instanz` für Betontyp anstelle von Typklasse?

data MyList a = End 
       |Entry a (MyList a) 

Statt deriving (Show) implementiert ich, dass explizit mich für alle MyList a wo a eine Instanz von Show ist.

instance Show a => Show (MyList a) 
    where show End = "" 
     show (Entry a l) = (show a) ++","++(show l) 

Das funktioniert einwandfrei. Nun wollte ich ändern, dass, so dass nur MyList String ist eine Instanz von Show und zu tun, so schrieb ich

instance Show (MyList String) 
    where show End = "" 
     show (Entry a l) = a ++","++(show l) 

Aber dies zu einem Fehler geführt hat, dass ich nicht verstehe:

Illegal instance declaration for `Show (MyList String)' 
    (All instance types must be of the form (T a1 ... an) 
    where a1 ... an are *distinct type variables*, 
    and each type variable appears at most once in the instance head. 
    Use FlexibleInstances if you want to disable this.) 
In the instance declaration for `Show (MyList String)' 

Jeder kann erklären, warum das nicht funktioniert und was dieser Fehler mir sagt?

Antwort

3

Der Fehler besagt, dass Standard-Haskell diese Art von Instanzdefinitionen nicht zulässt. Genau so, wie es sagt,

All instance types must be of the form (T a1 ... an) 
where a1 ... an are *distinct type variables*, 
and each type variable appears at most once in the instance head. 

Einer der Gründe dafür ist, dass, falls Sie beide Ihre Instanz Definitionen lassen, wird der Compiler weiß nicht, was man für MyList String, da sie beiden Spiele zu wählen. (Vielleicht möchten Sie auch einen Blick auf die rules for overlapping instances.)

Mit dieser Einschränkung auf die Form der Instanztypen garantiert, dass Typchecking immer beendet wird, und während es natürlich gültig und typenprüfbare Programme mit Instanzen nicht in dieser Form Genau so funktioniert es: Einige Einschränkungen in Haskell sind konservativ.

In Ihrem speziellen Fall tun nur, was der Compiler schlägt (d. H. Aktivieren FlexibleInstances) wird den Trick tun und diese Erweiterung ist in Bezug auf Terminierung sicher.

+0

Also ohne 'FlexibleInstances' zu aktivieren kann ich nur' show' für ganze typeclasses, aber nicht für bestimmte Typen? – flawr

+0

Für einen Typkonstruktor (zB Ihre 'MyList :: * -> *') können Sie nur Klassen (zB 'Show') nur für die ganze" Typenfamilie "der Form' MyList a' gleichzeitig implementieren, nicht für bestimmte Personen wie 'MyList String' oder' MyList Bool'. – kirelagin

+0

Das ist übrigens genau der Grund, warum 'Show' den Hacky [' showList'] hat (https://hackage.haskell.org/package/base-4.9.1.0/docs/Prelude.html#v:showList) Methode. Sie möchten Listen von 'Char' anders als die Listen aller anderen Typen anzeigen, aber Sie können nicht einfach eine separate' Show [Char] '- Instanz in Standard-Haskell implementieren. – kirelagin

Verwandte Themen