Haskell fügt einen polymorphen Typ hinzu
Ich versuche, einem Datentyp ein polymorphes == hinzuzufügen. Ich habe den POLYEQ Var Var zu data Exp hinzugefügt und Eval1 und Eval2 hinzugefügt:
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}
data Exp = V Var
| B Bool
| L Exp
| A Exp Exp
| MyInt Int
| And Exp Exp
| Or Exp Exp
| Not Exp
| Mult Exp Exp
| UnaryNeg Exp
| LEQ Exp Exp
| LESST Exp Exp
| Add Exp Exp
| POLYEQ Var Var
data Var = VZ |VS Var
eval:: Exp -> Int
eval (MyInt e4) = e4
eval (UnaryNeg e10) = - (eval e10)
eval (Mult e11 e12) = eval e11 * eval e12
eval (Add e1 e2) = eval e1 + eval e2
eval0:: Exp -> Bool
eval0 (B e5) = e5
eval0 (Not e3) = not (eval0 e3)
eval0 (And e6 e7) = (eval0 e6) && (eval0 e7)
eval0 (Or e8 e9) = (eval0 e8) || (eval0 e9)
eval0 (LEQ e13 e14) = eval e13 <= eval e14
eval0 (LESST e15 e16) = eval e15 < eval e16
eval2:: Exp -> Var
eval2 (V e22) = e22
eval1:: a -> Bool
eval1 (POLYEQ e19 e20) = eval2 e19 == eval2 e20
Aber ich bekomme den folgenden Fehler;
Exp.hs: 37: 32: Fehler:
• Couldn't match expected type ‘Exp’ with actual type ‘Var’
• In the first argument of ‘eval2’, namely ‘e19’
In the first argument of ‘(==)’, namely ‘eval2 e19’
In the expression: eval2 e19 == eval2 e20
Exp.hs: 37: 45: Fehler:
• Couldn't match expected type ‘Exp’ with actual type ‘Var’
• In the first argument of ‘eval2’, namely ‘e20’
In the second argument of ‘(==)’, namely ‘eval2 e20’
In the expression: eval2 e19 == eval2 e20
Fehlgeschlagen, Module geladen: keine.
Wie kann ich das == polymorph machen?
bearbeiten:
eval1:: Exp -> Bool
eval1 (POLYEQ e19 e20) = eval e19 == eval e20
Die Datei wird jetzt geladen, aber wenn ich ti1 = POLYEQ (MyInt 4) (MyInt 7) gefolgt von eval1 ti1 ausführe, wird der folgende Fehler angezeigt:
: 100: 7: Fehler: • Der erwartete Typ 'Exp' konnte nicht übereinstimmen.
with actual type ‘Exp -> Exp -> Exp’
• Probable cause: ‘POLYEQ’ is applied to too few arguments
In the first argument of ‘eval1’, namely ‘POLYEQ’
In the expression: eval1 POLYEQ
In an equation for ‘it’: it = eval1 POLYEQ
Antworten
Es gibt verschiedene Probleme mit Ihrem Code. Um Ihr eigentliches Problem zu lösen, sollten Sie zunächst die Felder des POLYEQKonstruktors vom Typ machen Exp, nicht Var, da Sie sonst nur Variablen vergleichen können.
Zweitens sollten Sie die evalFunktion nicht in mehrere Definitionen wie diese aufteilen . Es sieht so aus, als hätten Sie dies getan, um verschiedene Arten von Ergebnissen von jedem zurückzugeben: Intoder Bool. Aber die Wirkung der Code auf diese Weise des Schreibens ist , dass alle diese Funktionen sind teilweise : eval0wird nur die Arbeit an einer Untergruppe von Ausdrücken und auf andere abstürzen, und Sie können nicht im Voraus wissen , welche Funktion auf einem beliebigen anrufen , Expohne zuerst untersuchen.
Ein einfacher herkömmlicher Ansatz besteht darin, eine Art von Werten hinzuzufügen , die sich aus der Bewertung ergeben, zum Beispiel:
data Val
= IntVal Int
| BoolVal Bool
Auf diese Weise können Sie Ihre Funktionen zu einer konsolidieren und das Ergebnis jedes Falls mit dem entsprechenden ValKonstruktor kennzeichnen . Außerdem müssen Sie nicht alle Variablen mit unterschiedlichen Namen benennen, da sie jeweils lokal sind.
eval :: Exp -> Val
-- Evaluation of literals: tag the value with its type.
eval (MyInt i) = IntVal i
eval (B b) = BoolVal b
-- Evaluation of integer operations: match on ‘IntVal’.
-- This will raise an error if the expression did not return an integer.
eval (UnaryNeg e) = let
IntVal i = eval e -- Unwrap result, asserting that it’s an integer.
in IntVal (- i) -- Rewrap in ‘IntVal’ after applying negation.
eval (Mult e1 e2) = let
IntVal i1 = eval e1
IntVal i2 = eval e2
in IntVal (i1 * i2)
-- Instead of just crashing, you may use explicit
-- pattern matching and handle the type error:
eval (Add e1 e2) = case (eval e1, eval e2) of
(IntVal i1, IntVal i2) -> IntVal (i1 + i2)
_ -> ... -- Decide what to do in the error case.
-- Fill in the remaining cases for each ‘Exp’ constructor.
Für den POLYEQFall müssen Sie die Ergebnisse der Bewertung abgleichen, um festzustellen, dass sie vom gleichen Typ sind, und entsprechend vergleichen:
eval (POLYEQ e1 e2) = case (eval e1, eval e2) of
(IntVal i1, IntVal i2) -> BoolVal (i1 == i2)
(BoolVal b1, BoolVal b2) -> BoolVal (b1 == b2)
_ -> ... -- What do you want to do in this case?
-- Return ‘BoolVal False’, raise an error, or something else?
Dies beschreibt jedoch nicht, wie Lambda-Ausdrücke ( L) und -Variablen ausgewertet werden. Dazu müssen Sie ein zusätzliches Argument hinzufügen eval, um die variable Umgebung zu enthalten (z. B. a [Val], wo VZvom Kopf VSnach oben und innerhalb des Endes nachgeschlagen wird), und einen weiteren Konstruktor Val, um einen Funktionswert mit seiner Umgebung zu speichern . Dies geht jedoch über den Rahmen Ihrer aktuellen Frage hinaus.