Для проекта нам было поручено написать императивный язык и выполнить его через Haskell. Парсер (опущен здесь) и части оценки выполнены. Теперь остается только закодировать эффекты. Манипулирование маленьким роботом.Выполнение операции ввода-вывода, но возврат другого типа
Учитывая следующий код:
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
Как бы я идти о выполнении функции sendToMotor
(которая возвращает IO()
) в моей функции оценивая evalMotorInstruct
, которая должна возвращать Env
? Я немного растерялся в том, как я выполнил бы свою «действие» - функцию и только верну свое Env
из функции оценки.
Обратите внимание, что текущий код для evalMotorInstruct
недействителен. Функция должна возвращать Env
, но на самом деле возвращает IO Env
Спасибо
Вы обнаружили одно из интересных свойств Haskell - его чистоту. Вы не можете выполнить операцию ввода-вывода и вернуть результат * не *, завернутый в IO. Это связано с тем, что функции Haskell не могут выполнять произвольные побочные эффекты; они должны быть чистыми. Вы * можете * вернуть 'IO Env', который, кажется, именно то, что вы ищете здесь, основываясь на использовании' do' и 'return'. –
@AlexisKing Означает ли это, что я должен преобразовать все мои другие функции «eval», чтобы вернуть IO Env? И «разворачивать» их в любой ситуации? – MrKickkiller
Возможно, вы захотите изучить свободную монаду, чтобы избежать фиксации 'IO'. http://www.haskellforall.com/2012/06/you-could-have-invented-free-monads.html – user2297560