编辑:为澄清起见,所有以integer op integer
形式出现的算术表达式均应按其应有的方式工作,但variable op integer
导致令人困惑的结果。
用我正在写的简单语言,我正在尝试实现用户定义的变量。我正在遵循“在48小时内编写自己的计划”指南来构建我的开发流程。我已经成功实现了变量实例化,使得表达式x:=4
的行为类似于WYS48的(define x 4)
,因为它们都返回4。
但是,当我尝试在算术表达式中使用x
时,却得到了异常的结果。
Henry > x:=4 4 Henry > <x+4> 76
起初我以为它是将x的ASCII值加到4,但这不是因为x的ASCII值是120,十六进制是78,所以我知道不是那样。我看不出程序中的错误在哪里。我怀疑它可能在我的函数
str2Int
中,主要是因为其中减去了48。下面是我的代码,用于评估算术,表达式和用于评估x
的函数。在这种情况下,当表达式为x:=0
时减去71似乎可以解决x
的实例化问题,但这并不是特别理想的解决方法。
eval :: Env -> HenryVal -> IOThrowsError HenryVal eval env val@(Atom _) = return val eval env val@(ABinOp _) = return val eval env (Assign var val) = eval env val >>= defineVar env var eval env (ABinary op x y) = return $ evalABinOp env x op y evalABinOp :: Env -> HenryVal -> ABinOp -> HenryVal -> HenryVal evalABinOp env (Atom a) Add (Integer b) = Integer ((toInteger (str2Int'(str2HenryStr (a)))) + b ) str2Int' :: HenryVal -> Integer str2Int' n = toInteger $ (ord (show n !! 1)) - 48 str2HenryStr :: String -> HenryVal str2HenryStr s = String $ s
我不确定它的相关性,但是下面是我用来实现变量赋值的代码
type Env = IORef [(String, IORef HenryVal)]
type ThrowsError = Either HenryError
type IOThrowsError = ExceptT HenryError IO
nullEnv :: IO Env
nullEnv = newIORef []
liftThrows :: ThrowsError a -> IOThrowsError a
liftThrows (Left err) = throwError err
liftThrows (Right val) = return val
runIOThrows :: IOThrowsError String -> IO String
runIOThrows action = runExceptT (trapError action) >>= return . extractValue
isBound :: Env -> String -> IO Bool
isBound envRef var = readIORef envRef >>= return . maybe False (const True) . lookup var
getVar :: Env -> String -> IOThrowsError HenryVal
getVar envRef var = do env <- liftIO $ readIORef envRef
maybe (throwError $ UnboundVar "Getting an unbound variable" var)
(liftIO . readIORef)
(lookup var env)
setVar :: Env -> String -> HenryVal -> IOThrowsError HenryVal
setVar envRef var value = do env <- liftIO $ readIORef envRef
maybe (throwError $ UnboundVar "Setting an unbound variable" var)
(liftIO . (flip writeIORef value))
(lookup var env)
return value
defineVar :: Env -> String -> HenryVal -> IOThrowsError HenryVal
defineVar envRef var value = do
alreadyDefined <- liftIO $ isBound envRef var
if alreadyDefined
then setVar envRef var value >> return value
else liftIO $ do
valueRef <- newIORef value
env <- readIORef envRef
writeIORef envRef ((var, valueRef) : env)
return value
bindVars :: Env -> [(String, HenryVal)] -> IO Env
bindVars envRef bindings = readIORef envRef >>= extendEnv bindings >>= newIORef
where extendEnv bindings env = liftM (++ env) (mapM addBinding bindings)
addBinding (var, value) = do ref <- newIORef value
return (var, ref)
编辑:为澄清起见,所有整数op整数形式的算术表达式均应按其应有的方式工作,但可变op整数会导致混淆的结果。用我正在写的简单语言,...
[除非您具有eval
的任何其他实现,否则任何变量都不会被评估为二进制操作的值(除赋值外)。让我们看一下eval
和evalABinOp
: