Für ein Projekt hatten wir die Aufgabe, eine imperative Sprache zu schreiben und über Haskell auszuführen. Der Parser (hier weggelassen) und Teile der Auswertung sind fertig. Jetzt bleibt nur noch die Wirkung zu kodieren. Einen kleinen Roboter manipulieren.IO-Aktion ausführen, aber anderen Typ zurückgeben
den folgenden Code Gegeben:
data Env = Env [Binding]
instance Show Env where
show (Env (x:xs)) = show x ++ ", " ++ show (Env xs)
show (Env []) = ""
data Binding = Binding (String,Int)
instance Show Binding where
show (Binding x) = fst x ++ " : " ++ show (snd x)
lookup' :: String -> Env -> Int
lookup' zoek (Env env) = case elemIndex zoek [fst x | Binding x <- env] of
Just y -> y
Nothing -> error "Not found"
eval :: Stmt -> Env -> Env
eval (Seq s) env = foldl (flip eval) env s
eval (Assign varName aexpr) env = evalAssign varName aexpr env
eval (If bool stmt1 stmt2) env = evalIf bool stmt1 stmt2 env
eval (While bool stmt) env = undefined
eval (MotorInstruct string aExpr) env = undefined
eval (SensorRead string) env = undefined
eval Skip env = env
evalAExpr :: AExpr -> Env -> Int
evalAExpr (IntConst int) _ = fromInteger int
evalAExpr (Neg a) env = - evalAExpr a env
evalAExpr (ABinary Add a b) env = evalAExpr a env + evalAExpr b env
evalAExpr (ABinary Subtract a b) env = evalAExpr a env - evalAExpr b env
evalAExpr (ABinary Multiply a b) env = evalAExpr a env * evalAExpr b env
evalAExpr (ABinary Divide a b) env = evalAExpr a env `div` evalAExpr b env
evalAExpr (Var x) env = getElementAtEnv env (lookup' x env)
where
getElementAtEnv (Env env) index = getSndFromBinding (env !! index)
getSndFromBinding (Binding (_,t)) = t
evalBExpr :: BExpr -> Env -> Bool
evalBExpr (BoolConst bool) _ = bool
evalBExpr (Not expr) env = not $ evalBExpr expr env
-- Boolean operators
evalBExpr (BBinary And a b) env = evalBExpr a env && evalBExpr b env
evalBExpr (BBinary Or a b) env = evalBExpr a env || evalBExpr b env
-- Relational operators
evalBExpr (RBinary Greater a b) env = evalAExpr a env > evalAExpr b env
evalBExpr (RBinary Less a b) env = evalAExpr a env < evalAExpr b env
evalBExpr (RBinary Equal a b) env = evalAExpr a env == evalAExpr b env
evalIf :: BExpr -> Stmt -> Stmt -> Env -> Env
evalIf expr s1 s2 env = if evalBExpr expr env
then
eval s1 env
else
eval s2 env
evalAssign :: String -> AExpr -> Env -> Env
evalAssign term s (Env env)= if term `elem` transform
then
Env (take (lookup' term (Env env)) env ++ [Binding (term, evalAExpr s (Env env))]++ drop (lookup' term (Env env) + 1) env)
else
Env (env ++ [Binding (term, evalAExpr s (Env env))])
where transform = [ fst ele | Binding ele <- env]
zoekMotor :: String -> Int
zoekMotor "left" = 0x9
zoekMotor "right" = 0xa
zoekMotor _ = error "No such motor"
sendToMotor :: String -> Int -> IO()
sendToMotor m s = do
bot <- openMBot
sendCommand bot $ setMotor (zoekMotor m) s s
closeMBot bot
evalMotorInstruct :: String -> AExpr -> Env -> Env
evalMotorInstruct welke waarde env = do
sendToMotor welke (evalAExpr waarde env)
return env
Wie würde ich mich über die Funktion Ausführen sendToMotor
in meiner Bewertungsfunktion (die IO()
zurückgibt) evalMotorInstruct
die eine Env
zurückgeben sollte? Ich bin etwas zu sehr darüber im Unklaren, wie ich meine 'action' - Funktion ausführen und nur meine Env
wieder aus der Auswertungsfunktion herausholen würde.
Beachten Sie, dass der aktuelle Code für evalMotorInstruct
nicht korrekt ist. Die Funktion soll eine Env
zurück, aber tatsächlich gibt ein IO Env
Danke
Sie haben eine der interessanten Eigenschaften von Haskell-seine Reinheit entdeckt. Sie können keine E/A-Aktion ausführen und ein in IO eingeschlossenes Ergebnis * not * zurückgeben. Dies liegt daran, dass Haskell-Funktionen keine beliebigen Nebenwirkungen ausführen können. Sie müssen rein sein. Sie * könnten * ein 'IO Env' zurückgeben, das hier zu sein scheint, basierend auf Ihrer Verwendung von' do' und 'return'. –
@AlexisKing Bedeutet dies, dass ich alle meine anderen "eval" -Funktionen konvertieren sollte, um auch IO Env's zurückzugeben? Und sie "auspacken" in jeder Situation? – MrKickkiller
Vielleicht möchten Sie sich mit einer freien Monade beschäftigen, um zu vermeiden, dass Sie sich an 'IO' binden. http://www.haskellforall.com/2012/06/you-could-have-vent-free-monads.html – user2297560