2016-09-22 10 views
0

ich aber eine ‚einfache‘ Beispiel schreibe Typklassen für die Implementierung ich herauszufinden, eine harte Zeit habe, warum dies nicht kompiliert:Typ konnte nicht in Instanz erwartet übereinstimmen

class Euclidean a where 
    norm :: (Euclidean a, Floating b) => a -> b 

data Point a b = Point a b 

instance (Floating x, Floating y) => Euclidean (Point x y) where 
    norm (Point x y) = x 

Es scheitert mit:

Couldn't match expected type ‘b’ with actual type ‘x’ 
    ‘x’ is a rigid type variable bound by 
     the instance declaration at src/Simple.hs:10:10 
    ‘b’ is a rigid type variable bound by 
     the type signature for 
     norm :: (Euclidean (Point x y), Floating b) => Point x y -> b 
     at src/Simple.hs:11:3 
Relevant bindings include 
    x :: x (bound at src/Simple.hs:11:15) 
    norm :: Point x y -> b (bound at src/Simple.hs:11:3) 
In the expression: x 
In an equation for ‘norm’: norm (Point x y) = x 

Hinweis: Die gewünschte Funktionsimplementierung wäre natürlich sqrt $ (x * x) + (y * y).

Antwort

3

die genau auf die in der Definition der Klasse verwiesen Arten Werfen wir einen Blick:

class Euclidean a where 
    norm :: (Euclidean a, Floating b) => a -> b 

Die a in der zweiten Zeile wird durch die a in der ersten Zeile gebunden. Aber die b ist an nichts gebunden, daher wird sie implizit allgemein quantifiziert. Mit anderen Worten ist die obige Definition entspricht

class Euclidean a where 
    norm :: forall b. (Euclidean a, Floating b) => a -> b 

So wird für jeden Typ Euclideana, norm Funktion ist, die für jede Floating b einen a Wert und gibt einen b Wert annimmt.

So im Beispiel mit Point, die Dummy-Definition norm, die Sie zur Verfügung gestellt, kehrt immer von Wert vom Typ x während der Compiler Sie eine Implementierung liefern erwartet, dass Werte von beliebigen Floating Typen zurückgibt.

Also, wie lösen Sie das? On-Lösung ist, so etwas zu tun:

instance (Real x, Floating x, Floating y) => Euclidean (Point x y) where 
    norm (Point x y) = realToFrac x 

ich eine Real x Einschränkung hinzugefügt habe, so dass ich realToFrac auf x nennen kann einen beliebigen Floating-Wert zu erhalten. Beachten Sie, dass es wahrscheinlich sinnvoller ist, Ihre Floating Einschränkung durch RealFrac zu ersetzen.

+0

Danke für Ihre schnelle Antwort. Jetzt gibt es ein anderes Problem: Wie kann ich den Typ von "x" an den Typ von "y" anpassen? Ich schrieb die Implementierung als 'Norm (Punkt xy) = realToFrac $ sqrt $ (x * x) + (y * y)' (Hinzufügen der Real-Einschränkung zu beiden Typen in der Instanz-Header), aber jetzt klagt es dass es 'x' mit' y' nicht übereinstimmen kann – Midiparse

+0

Versuchen Sie etwas wie 'instance (Real x, Floating x) => Euklidisch (Punkt xx) where' – redneb

+0

Es beschwert sich, dass es verschiedene Typ Variablen dort benötigt, und FlexibleConstraints hinzufügen zu erlauben dies – Midiparse

Verwandte Themen