2013-02-01 12 views
32

Ich bin neu bei Haskell, und ich habe Probleme mit dem Debuggen meines Codes. Das Beheben eines Fehlers führt zu anderen Fehlern ...Keine Instanz für (Fractional Int), die sich aus einer Verwendung von `/ 'ergibt

Hier ist mein Code.

import Data.Maybe 

data Op = Add | Sub | Mul | Div | And | Or | Not | Eq | Less | Great 
    deriving (Eq, Show) 

data Exp = Literal Value 
    | Primitive Op [Exp] 
    | Variable String 
    | If Exp Exp Exp 
    | Let [(String, Exp)] Exp 
    deriving (Show, Eq) 

data Value = Number Int 
     | Bool Bool 
     | String String 
    deriving (Eq, Show) 

type Env = [(String, Value)] 

eval :: Env -> Exp -> Value 
eval e (Literal v) = v 
eval e (Variable x) = fromJust (lookup x e) --22 

prim :: Op -> [Value] -> Value 
prim Add [Number a, Number b] = Number (a + b) 
prim And [Bool a, Bool b] = Bool (a && b) 
prim Sub [Number a, Nuamber b] = Number (a - b) -- No instance for (Fractional Int) arising from a use of `/' 
prim Mul [Number a, Number b] = Number (a * b) 
prim Div [Number a, Number b] = Number (a/b) 
prim Or [Bool a, Bool b] = Bool (a || b) 
prim Not [Bool a] = Bool (not a) 
prim Eq [Number a, Number b] = Bool (a == b) 
prim Eq [String a, String b] = Bool (a == b) 
prim Less [Number a, Number b] = Bool (a < b) 
prim Less [String a, String b] = Bool (a < b) 
prim Great [Number a, Number b] = Bool (a > b) 
prim Great [String a, String b] = Bool (a > b) --37 

main = do 
    eval [("y", (Number 40))] (Let [("x", (Literal (Number 2)))] (prim Add [(Variable "x"), (Variable "y")])) -- Couldn't match expected type `Exp' with actual type `Value' 

Ich bekomme jetzt zwei Fehler, die ich in Kommentaren geschrieben habe. Wenn Sie wissen, was mit meinem Code falsch ist, teilen Sie Ihre Idee und speichern Sie meine Zeit ...

Vielen Dank.

+0

Meinen Sie "Zahl (div a b)" oder seine Infix-Version? –

Antwort

52
-- No instance for (Fractional Int) arising from a use of `/' 

Vermutlich kommt das ist von dieser Linie, anstatt die eins mit deinem Kommentar:

prim Div [Number a, Number b] = Number (a/b) 

a und b sind Int s. Der Abteilungsoperator ist (/) :: Fractional a => a -> a -> a (Sie können das herausfinden, indem Sie ghci hochfeuern und :t (/) oder looking it up on Hoogle eingeben).

Wenn Sie nicht Typen wie Fractional a => a -> a -> a gesehen, sollten Sie diese in zwei Teile lesen:

  1. Der Kontext Fractional a
  2. Der Typ a -> a -> a

Das ist wie eine reguläre a -> a -> a Geben Sie zwei Argumente eines Typs ein und geben Sie ein Ergebnis desselben Typs zurück.Der einzige Unterschied beim Hinzufügen des Kontextes Fractional a ist, dass der für a verwendete Typ eine Instanz der Klasse Fractional sein muss. Es ist nicht frei, über irgendeinen Typ zu verfügen, den Sie mögen.

Wenn Sie noch nicht über Klassen gelernt haben, machen Sie sich keine Sorgen. Sie sind ziemlich leicht zu begreifen, aber nicht etwas, das man genau betrachten sollte, wenn man gerade anfängt; Du wirst später zu ihnen kommen.

Int ist kein Mitglied der Fractional Typklasse, so dass die / Betreiber nicht auf Int s funktionieren.

Der Grund ist, dass regelmäßige mathematische Division nicht arbeiten auf Ganzzahlen mit diesem Typ; 3/2 müsste entweder 1.5 geben, in diesem Fall passt es nicht zum Typ Int -> Int -> Int, oder geben 1 oder 2, in diesem Fall wäre es nicht korrekt mathematische Division. Es gibt eine Funktion div zur Implementierung integer division, verwendbar wie a `div` b in Infix-Notation.

-- Couldn't match expected type `Exp' with actual type `Value' 

Diese Nachricht handelt von Ihren eigenen Typen, in einem einzigen Ausdruck, den Sie geschrieben haben. Und die tatsächliche vollständige Fehlermeldung hätte Ihnen mehr Kontext darüber gegeben, welcher Teil des Ausdrucks den Fehler enthält. Folgen Sie einfach von oben nach unten und überprüfen Sie die Art der Dinge selbst und der Fehler springt sehr schnell auf Sie zu.

In diesem Fall erhalten Sie hier:

Let [("x", (Literal (Number 2)))] (prim Add [(Variable "x"), (Variable "y")]) 

Let braucht zwei Argumente, eine [(String, Exp)] und eine Exp. Die Liste ist in Ordnung, aber das zweite Argument ist (prim Add [(Variable "x"), (Variable "y")]). Ohne in die Unterkonstruktion zu graben, um zu sehen, ob sie korrekt ist, hat prim den Typ Op -> [Value] -> Value, also gibt es keine Möglichkeit, dass es Ihnen einen Exp gibt.

Wie Sie das beheben, liegt an Ihnen; Es sieht so aus, als ob Sie für die gesamte Unterscheidung zwischen Ausdruck und Wert ein wenig Refactor benötigen. prim gibt Ihnen eine Value, die Sie einfach Wrap in einem Literal anwenden können, um Sie über den Typfehler zu bekommen, den Sie erhalten, aber dann stoßen Sie auf das Problem, dass eine Op und eine [Value] nehmen sollte, aber Sie scheinen zu haben gab es eine Op und eine [Exp] (mit Variablen). Ich denke, dass Sie über den Unterschied zwischen prim zur Berechnung der Ergebnisse einer primitiven Anwendung denken müssen, mit dem Primitive Konstruktor von Exp zu eine primitive Anwendung darstellen und eval verwenden, um (in einer Umgebung) einen beliebigen Ausdruck zu bewerten (die kann mehrere primitive Anwendungen enthalten).

+0

oops, mein schlechtes. Ich habe den Kommentar in die falsche Zeile gesetzt. – Nayana

+0

Vielen Dank, dass Sie sich die Zeit genommen haben, meine Frage freundlich zu beantworten. – Nayana

+0

Es tut mir leid, aber was bedeutet das "(/) :: Fractional a => a -> a -> a" gemein? Es bedeutet, dass es ein und ein anderes als Parameter nimmt und gibt zurück, richtig? aber was ist gemein? Woher soll ich wissen, dass Int kein Mitglied der Fractional type-Klasse ist? – Nayana

19

Das Problem, das Sie haben, ist, dass Haskell verschiedene Funktionen für Integer und "Bruch" Division hat. Integer-Division schneidet ab, Teilbruch nicht. Also statt

prim Div [Number a, Number b] = Number (a/b) 

wollen Sie

prim Div [Number a, Number b] = Number (a `div` b) 

Was die Fehlermeldung tun, tatsächlich bedeutet, dass die Funktion (/) Teil der Fractional Klasse. Dies ist im Grunde eine Schnittstelle, die verschiedene Typen implementieren können. Um Informationen über sie GHCI Feuer und tun

Prelude> :i (/) 
class Num a => Fractional a where 
(/) :: a -> a -> a 
... 
-- Defined in `GHC.Real' 
infixl 7/

Prelude> :i Int 
data Int = GHC.Types.I# GHC.Prim.Int# -- Defined in `GHC.Types' 
instance Bounded Int -- Defined in `GHC.Enum' 
instance Enum Int -- Defined in `GHC.Enum' 
instance Eq Int -- Defined in `GHC.Classes' 
instance Integral Int -- Defined in `GHC.Real' 
instance Num Int -- Defined in `GHC.Num' 
instance Ord Int -- Defined in `GHC.Classes' 
instance Read Int -- Defined in `GHC.Read' 
instance Real Int -- Defined in `GHC.Real' 
instance Show Int -- Defined in `GHC.Show' 

Die erste gibt Ihnen Informationen über die Funktion (/): es Ihnen sagt, dass es in der Klasse Fractional. Dann, wenn Sie :i Int es zeigt Ihnen alle Instanzen für Int. Beachten Sie, dass Int keine Instanz von Fractional ist, so dass Sie (/) mit Int nicht verwenden können.

Noch ein Tipp: Die Backticks (`) eine Funktion in einem Infixoperator drehen, so

a `div` b 

ist die gleiche wie

div a b 
+0

Vielen Dank, haben Sie eine Idee für den zweiten Fehler? – Nayana

+0

Nun, Ben war schneller ... – Paul

+0

'div' Betreiber woks für mich –

Verwandte Themen