2012-12-31 9 views
6

sein könnte, ich bin ziemlich neu in Haskell, so dass ich hoffe, dass dies nicht eine dumme Frage ist. Ich habe diesen Datentyp:eine Funktion mit Argumenten Anwendung, die entweder Ints oder Double

data N = I Int | D Double deriving (Show, Eq) 

Ich versuche, eine Funktion mit der Signatur (Num a) => (a -> a -> a) -> N -> N -> N zu schreiben, die die Funktion auf die Zahlen innerhalb des N s gelten und gibt einen N mit dem Ergebnis. Wenn die N s beide s sind, sollte sie nur die Funktion anwenden und eine ; wenn man eine I ist und der andere ist ein D, sollte es die Int im I auf eine Double gelten die Funktion auf die zwei Double s konvertieren, und gibt eine D; und wenn beide I s sind, sollte sie die Funktion anwenden und eine I zurückgeben. Hier ist der (gebrochen) Code, den ich bisher habe:

widen :: N -> N -> (N, N) 
widen (I i) [email protected](D _) = (D (fromIntegral i), d) 
widen [email protected](D _) [email protected](I _) = widen i d 
widen x y = (x, y) 

numOp :: (Num a) => (a -> a -> a) -> N -> N -> N 
numOp op x y = case widen x y of (D x', D y') -> D $ x' `op` y' 
           (I x', I y') -> I $ x' `op` y' 

ich einen Fehler auf beiden Leitungen von numOp, though. Die erste ist:

Could not deduce (a ~ Double) 
from the context (Num a) 
    bound by the type signature for 
      numOp :: Num a => (a -> a -> a) -> N -> N -> N 
    at <line num> 
In the second argument of `($)', namely x' `op` y' 
In the expression: D $ x' `op` y' 
In a case alternative: (D x', D y') -> D $ x' `op` y' 

Und die zweite:

Couldn't match type `Double' with `Int' 
Expected type: Int 
    Actual type: a 
In the second argument of `($), namely x' `op` y' 
In the expression: I $ x' `op` y' 
In a case alternative: (I x', I y') -> I $ x' `op` y' 

Ich bin ziemlich sicher, ich verstehe, was beide Fehler bedeuten; Ich denke, der erste zu sagen, dass die Informationen in meiner Art Unterschrift ist nicht genug für GHC davon ausgehen, dass op eine Double zurückgibt, die von der D Wert Konstruktor erforderlich ist, und der zweite sagt, dass da die erste Zeile bedeutet, dass a ist Double, kann diese Linie nicht einen Wert vom Typ verwenden a, als ob es ein Int ist. Ich habe keine Ahnung, wo ich anfangen soll, nach dem richtigen Weg zu suchen.

Wenn es hilft, ist der Grund, warum ich versuche, dies zur Arbeit zu bringen, dass ich zusammen mit dem Write Yourself a Scheme tutorial folgen; Alle Beispiele im Tutorial (speziell in der Evaluation section) befassen sich nur mit Ganzzahlen, aber als eine Übung möchte ich die Fähigkeit hinzufügen, sowohl Integral- als auch Gleitkommazahlen zu unterstützen, so dass z.B. (+ 1 2.5 2.5) gibt 6.0 zurück und (+ 1 2 3) gibt 6 zurück. Wenn ich über den falschen Weg nachdenke oder es einen einfacheren Weg gibt, dies zu erreichen, würde ich gerne Vorschläge hören.

+0

Keine dumme Frage überhaupt. Das Problem ist nicht offensichtlich. –

Antwort

7

Die Signatur

numOp :: (Num a) => (a -> a -> a) -> N -> N -> N 

sagt, dass jede numOpa -> a -> a für jede bestimmte Instanz Num und zwei N s und von diesen monomorphen Funktion vom Typ nimmt berechnet ein N. So zum Beispiel eine Funktion vom Typ

Complex Float -> Complex Float -> Complex Float 

oder

approxRational :: RealFrac a => a -> a -> Rational 

(spezialisiert auf a = Rational) wären legitim erste Argumente.

Was Sie brauchen, ist eine polymorphe Funktion, die alle Num Instanzen als erstes Argument umgehen kann, das heißtder Rang 2 Typ

numOp :: (forall a. Num a => a -> a -> a) -> N -> N -> N 

(Sie müssen die RankNTypes Spracherweiterung für das).

+0

Super, vielen Dank! – jcsmnt0

+1

Wenn Sie nur mit Rank-2-Typen arbeiten, im Gegensatz zu höheren Rank-Typen, können Sie stattdessen 'Rank2Types' verwenden. Dies hat den Vorteil, dass es die entscheidungsentscheidende Inferenz bewahrt (die bei höherrangigen Typen fehlschlägt), obwohl ich dies in der Praxis nie gesehen habe. –

+1

Würden Sie etwas weiter erklären, was Sie damit meinen? Ich dachte, dass das Beibehalten der entscheidbaren Inferenz bedeuten würde, dass ich die explizite Typ-Signatur aus meiner "numOp" -Funktion entfernen könnte und der Compiler würde sie erfolgreich ableiten, wenn ich das Pragma "Rank2Types" hätte, aber das scheint nicht der Fall zu sein . – jcsmnt0

Verwandte Themen