Der Compiler-Fehler ist hier hilfreich, aber nur auf diese nervige Art und Weise, wo er Ihnen genau sagt, was falsch ist, aber nicht warum ist es falsch.
Erwartet einen Typ, aber "Rep a" hat Art "* -> *".
Also hier das Problem ist, dass Rep
(eine Art Familie) zwei Argumente benötigt (nennen wir sie a
und p
, wie in Rep a p
); Als Typ-Level-Funktion werden diese beiden Typargumente dem Typ "generic" zugeordnet. Zum Beispiel
data Empty deriving Generic
instance Generic Empty where
type Rep Empty =
D1 ('MetaData "Empty" "Main" "package-name" 'False) V1
-- taken from https://hackage.haskell.org/package/base-4.9.0.0/docs/GHC-Generics.htm
a
, z.B. Empty
, repräsentiert den Typ, aus dem wir generisch sind.
p
ist ein Dummy-Typ, so dass wir unsere Darstellungsarten für höhere Typen (see Generic1
in the documentation) wiederverwenden können.
So, in dem obigen Beispiel würde Rep Empty p
-D1 ('MetaData ...) V1 p
vereinfachen.
Wir können normalerweise ignorieren, außer wenn es darum geht, neue Typklassen zu definieren, die Vorteile von Generika nutzen. Wir möchten, dass Muster auf Typen wie D1 ('MetaData ...) V1 p
pattern, aber wir brauchen einen Weg, den zusätzlichen Parameter zu behandeln.
Ein Trick ist dann, D1 ('MetaData ...) V1
wie ein höherer Typ (wie ein Funktor) zu behandeln. Dies ist unsere f
in GDefault
.
class GDefault f where
gdef :: f a
Ja a
wird immer dieser blöde Parameter, die wir nie verwenden, aber im Gegenzug für Leitungsrauschen wir die Fähigkeit zur Mustererkennung auf den f
in unseren Fällen bekommen. Hier sind vier Instanzen, die für die automatischen generische def
Implementierungen für die Produktart ermöglichen (:*:
ein angehobenes Tupel ist):
instance GDefault U1 where
gdef = U1
instance Default a => GDefault (K1 i a) where
gdef = K1 def
instance (GDefault a, GDefault b) => GDefault (a :*: b) where
gdef = gdef :*: gdef
instance GDefault a => GDefault (M1 i c a) where
gdef = M1 gdef
Dies, zusammen mit einigen sinnvollen Standardwerten für den numerischen Turm, lassen Sie uns Datentypen definieren wie data Foo = Foo Int Char Float deriving (Show, Generic)
und bewerten show (def :: Foo)
bis "Foo 0 0 0.0"
.
Ihr Code hatte gdef :: a
, was die falsche Art ist.Wir wollen gdef :: f a
, weil die typeclass auf Typen mit Art * -> *
definiert ist, daher die Fehlermeldung.
und Vorteil dieser Hilfsklasse zu nehmen, tun wir viel, wie Sie tat:
class Default a where
def :: a
default def :: (Generic a, GDefault (Rep a)) => a
def = to gdef
to :: Rep a x -> a
eine falsche x
einführt, die mit unseren gdef :: f a
vereint f ~ Rep a
zu produzieren, die x
Wegwerfen und genau das, was wir haben es beabsichtigt.
You can see this approach elaborated in the data-default
package.
Die erste Klasse erwartet, dass seine "Argument" 'f' Art haben' * -> * '(da es verwendet sie als' fa'), aber die Klasse Argument 'a' (von' GDefault') erwartet nur einen Typ (so freundlich '*'), aber Sie füttern es immer noch etwas von Art '* -> *'. – Alec
Es ist sehr unklar, was diese Frage fragt - der Typchecker * hat Ihnen gesagt, warum der letztere Code nicht kompiliert! Auch wenn Ihr "Problem" darauf zurückzuführen ist, sollten Sie vielleicht das eigentliche Problem beschreiben. – user2407038
Ich fühle mich ziemlich dumm, es ist genau das, was Alec vorschlägt ... – fakedrake