我已经陷入了以下困境。
evalAExpr :: AExpr -> Env -> Int
evalAExpr (Var x) env = actAccordingly (getValueOfBinding env x)
where
actAccordingly (Left int) = int
actAccordingly (Right stmt) = eval stmt env
eval :: Stmt -> Env -> IO Env`
getValueOfBinding :: Env -> String -> Either Integer Stmt
所以需要发生的是,从Either Monad得到的Stmt x
,它应该评估x
(由于其他进程,需要在IO
中进行评估)进入一个新的环境,之后我可以从环境中返回正确的值。但是,根据我对Haskell的有限知识,我无法摆脱IO
。
例如:givetheCorrectThing nameOfTheValueInTheEnv (eval stmt env)
永远不会使用当前代码,因为所有evalAExpr
函数(是的,只有1个)都返回一个Env atm。如果我必须改变它,它将导致添加所有评估do和return语句。 > 50-60次出现。当然。这会使代码看起来如此混乱。我需要IO的原因是因为这个评估必须(在某个时候)并从mBot(http://makeblock.com/mbot-stem-educational-robot-kit-for-kids/)收集数据,以及从键盘收集数据(通过getLine完成)
你们中的任何人都有办法重新编写这些代码,以便我能保持整洁有序吗?
如果需要更多代码:请随意ping /提及我。我将提供所要求的代码行。
根据要求提供更多代码:
-- 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
答案 0 :(得分:2)
从我对Haskell的有限知识中,我无法摆脱IO
正确†!并且有充分的理由:使用当前的签名,任何使用你的函数的人都知道这真的只是一个纯粹的,引用透明的计算,所以他们可以相应地粗心大意(懒惰等)。如果你被允许只通过签名放入一些IO
而没有明确说明,你可能很容易打破每个人的代码!
当然,如果你只是注意到你需要做IO,那么你确实处于一种两难的境地。现在没有好办法改变所有签名。
但是,你可以通过首先使用类型同义词‡来阻止这种情况:如果你原来是
type Evaluation a = Identity a
-- ... lots of functions with an `Evaluation` result ...
evalAExpr :: AExpr -> Env -> Evaluation Int
evalAExpr (Var x) env = actAccordingly (getValueOfBinding env x)
where
actAccordingly (Left int) = return int
actAccordingly (Right stmt) = someThingThatDidn'tYetRequireIO
然后,在注意到您需要IO
之后,您可能刚刚将其更改为
type Evaluation a = IO a
{- same as before:
evalAExpr :: AExpr -> Env -> Evaluation Int
evalAExpr (Var x) env = actAccordingly (getValueOfBinding env x)
where
actAccordingly (Left int) = return int -}
actAccordingly (Right stmt) = eval stmt env
在一个大项目中,Evaluation
monad通常是一个monad变换器堆栈,你只需为它下面的IO添加一个额外的层。
† 如果有人提醒我function that shall not be named,我会打击他们关于头with a nuclear missile。
‡ 正如dfeuer所说,newtype
可能更好。
答案 1 :(得分:1)
您必须编写evalAExpr
我们会调用新版本evalAExprIO
:
evalAExprIO :: AExpr -> Env -> IO Int
evalAExpr (Var x) env = actAccordingly (getValueOfBinding env x)
where
actAccordingly (Left int) = return int
actAccordingly (Right stmt) = eval stmt env
实际上只有一个重大变化 - 在Left
案例中
函数actAccordingly
使用return int
而不是int
。
evalAExprIO
的类型签名已更改,但这是一个问题
GHC可以推断,所以你不必知道如何改变。
<强>更新强>
变化:
evalBExpr (RBinary Greater a b) env = evalAExpr a env > evalAExpr b env
为:
evalBexpr (RBinary Greater a b) env = liftM2 (>) (evalAExpr a env) (evalExpr b env)
(为liftM2导入Control.Monad。)