Haskell dodaje typ polimorficzny
Próbuję dodać polimorficzny == do typu danych. Dodałem POLYEQ Var Var do Data Exp i dodałem Eval1 i 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
Ale pojawia się następujący błąd;
Exp. Hs: 37: 32: błąd:
• 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: błąd:
• 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
Niepowodzenie, załadowano moduły: brak.
Jak mogę ustawić == polimorficzny?
edytować:
eval1:: Exp -> Bool
eval1 (POLYEQ e19 e20) = eval e19 == eval e20
Plik ładuje się teraz, ale po uruchomieniu ti1 = POLYEQ (MyInt 4) (MyInt 7), a następnie eval1 ti1, pojawia się następujący błąd:
: 100: 7: błąd: • Nie można dopasować oczekiwanego typu „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
Odpowiedzi
Istnieje kilka problemów z Twoim kodem. Po pierwsze, aby rozwiązać swój rzeczywisty problem, powinieneś utworzyć pola POLYEQkonstruktora typu Exp, a nie Var, w przeciwnym razie będziesz mógł tylko porównać zmienne.
Po drugie, nie powinieneś dzielić evalfunkcji na wiele takich definicji. Wygląda na to, że zrobiłeś to, aby zwrócić różne typy wyników z każdego z nich: Intlub Bool. Ale efekt pisania kodu w ten sposób jest taki, że wszystkie te funkcje są częściowe : eval0będą działać tylko na podzbiorze wyrażeń i będą się zawieszać na innych, a nie możesz z wyprzedzeniem wiedzieć, którą funkcję wywołać w dowolnej funkcji Expbez najpierw go zbadać.
Prostym konwencjonalnym podejściem jest dodanie typu wartości wynikających z oceny, na przykład:
data Val
= IntVal Int
| BoolVal Bool
Dzięki temu możesz skonsolidować swoje funkcje w jedną i oznaczyć wynik każdego przypadku odpowiednim Valkonstruktorem. Ponadto nie musisz nazywać wszystkich swoich zmiennych różnymi nazwami, ponieważ są one lokalne dla każdego przypadku.
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.
W tym POLYEQprzypadku musisz dopasować wyniki oceny, aby potwierdzić, że są tego samego typu, i odpowiednio porównać:
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?
Jednak to nie opisuje, jak oceniać wyrażenia lambda ( L) i zmienne. W tym celu musisz dodać dodatkowy argument evalzawierający zmienną environment (na przykład a [Val], gdzie VZspogląda w górę od głowy i VSpatrzy w górę) oraz inny konstruktor Valdo przechowywania wartości funkcji w swoim środowisku . Jednak to wykracza poza zakres twojego obecnego pytania.