gpt4 book ai didi

haskell - 语言设计 : Confusion as to why an assigned variable returns the wrong answer in arithmetic expressions

转载 作者:行者123 更新时间:2023-12-04 09:56:01 25 4
gpt4 key购买 nike

编辑:为了澄清起见,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)

最佳答案

除非你有任何其他的 eval 实现,任何变量都不会被评估为其二元运算的值(除了赋值)。一起来看看evalevalABinOp :

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 -- defineVar returns val
eval env (ABinary op x y) = return $ evalABinOp env x op y -- evalABinOp uses env?

evalABinOp :: Env -> HenryVal -> ABinOp -> HenryVal -> HenryVal
evalABinOp env (Atom a) Add (Integer b) = Integer ((toInteger (str2Int'(str2HenryStr (a)))) + b )
-- env is not used on the right hand side!

因为你从不使用 env在右侧,我们可以 100% 确定 Atom a不能解释为变量,但必须解释为数字或字符串(或 undefined variable )。您实际上没有在代码中查找 a在当前环境中的值(value)。相反,您转换 x成整数:
str2Int' :: HenryVal -> Integer
str2Int' n = toInteger $ (ord (show n !! 1)) - 48

str2HenryStr :: String -> HenryVal
str2HenryStr s = String $ s

我也没有 HenryVal的定义及其 Show手头的实例,所以我只能假设 show (String "x")结果 "\"x\""因此 "\"x\"" !! == 'x' . ord 'x' - 48120 - 48 = 72 .添加 4 ,你最终会得到 76 .算术按预期工作。 您根本不使用指定的值 .相反,您甚至不解释 Atom作为变量,但作为一位数的 ASCII 数字。

话虽如此,解决方案会是什么样子?嗯,是这样的:
evalABinOp :: Env -> HenryVal -> ABinOp -> HenryVal -> IOThrowsError HenryVal
evalABinOp env (Integer a) Add (Integer b) = return $ Integer $ a + b
evalABinOp env (Atom a) op b@(Integer _) = getVar env a >>= (\c -> evalABinOp env c op b)

而不是使用 a立即,我们首先查找值。请注意,这仅在您的解析器将数字解释为 Integer 时才有效。在您的 HenryVal语。请注意,没有 str2Int魔法在继续:在我们使用 x 之前,所有这些都应该得到处理。 , 除非我们想允许添加字符串。

关于haskell - 语言设计 : Confusion as to why an assigned variable returns the wrong answer in arithmetic expressions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61924182/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com