语言设计:关于为什么分配的变量在算术表达式中返回错误答案的困惑

问题描述 投票:0回答:1

编辑:为澄清起见,所有以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整数会导致混淆的结果。用我正在写的简单语言,...

haskell evaluation language
1个回答
0
投票

[除非您具有eval的任何其他实现,否则任何变量都不会被评估为二进制操作的值(除赋值外)。让我们看一下evalevalABinOp

© www.soinside.com 2019 - 2024. All rights reserved.