Haskell ajoutant un type polymorphe
J'essaye d'ajouter un polymorphe == à un type de données. J'ai ajouté le POLYEQ Var Var aux données Exp et ajouté Eval1 et Eval2:
{-# 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
Mais j'obtiens l'erreur suivante;
Exp.hs: 37:32: erreur:
• 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: erreur:
• 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
Échec, modules chargés: aucun.
Comment puis-je rendre le == polymorphe?
Éditer:
eval1:: Exp -> Bool
eval1 (POLYEQ e19 e20) = eval e19 == eval e20
Le fichier se charge maintenant, mais lorsque j'exécute ti1 = POLYEQ (MyInt 4) (MyInt 7) suivi de eval1 ti1, j'obtiens l'erreur suivante:
: 100: 7: erreur: • Impossible de correspondre au type attendu "Exp"
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
Réponses
Il y a plusieurs problèmes avec votre code. Tout d'abord, pour résoudre votre problème réel, vous devez rendre les champs du POLYEQconstructeur de type Exp, non Var, sinon vous ne pourrez comparer que des variables.
Deuxièmement, vous ne devez pas diviser la evalfonction en plusieurs définitions comme celle-ci. Il semble que vous l'ayez fait pour renvoyer différents types de résultats pour chacun: Intou Bool. Mais l'effet d'écrire votre code de cette façon est que toutes ces fonctions sont partielles : eval0volonté que le travail sur un sous - ensemble d'expressions, et se bloque sur les autres, et vous ne pouvez pas savoir à l' avance quelle fonction de faire appel à un arbitraire Expsans l'examinant en premier.
Une approche conventionnelle simple consiste à ajouter un type de valeurs résultant de l'évaluation, par exemple:
data Val
= IntVal Int
| BoolVal Bool
Avec cela, vous pouvez consolider vos fonctions en une seule et étiqueter le résultat de chaque cas avec le Valconstructeur approprié . De plus, vous n'avez pas besoin de nommer toutes vos variables avec des noms distincts, car elles sont locales à chaque cas.
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.
Pour le POLYEQcas, vous devez faire correspondre les résultats de l'évaluation pour affirmer qu'ils sont du même type et comparer en conséquence:
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?
Cependant, cela ne décrit pas comment évaluer les expressions lambda ( L) et les variables. Pour cela, vous devrez ajouter un argument supplémentaire pour evalcontenir la variable d'environnement (par exemple, a [Val], où VZregarde de la tête et VSregarde dans la queue), et un autre constructeur pour Valstocker une valeur de fonction avec son environnement . Cependant, cela dépasse le cadre de votre question actuelle.