作为 Haskell 的新手,我目前正在尝试通过为简单的命令式玩具语言编写解释器来提高我的技能。
这种语言中的一个表达式是input
,它从标准输入中读取一个整数。但是,当我将此表达式的值分配给一个变量,然后稍后再使用此变量时,似乎我实际上存储了读取值的计算而不是读取值本身。这意味着例如语句
x = input;
y = x + x;
将导致解释器调用输入过程3次而不是 1 次。
在评估器模块内部,我使用 aMap
来存储变量的值。因为我需要处理 IO,所以它被包裹在一个IO
monad 中,如下面的最小示例中所述:
import qualified Data.Map as Map
type State = Map.Map String Int
type Op = Int -> Int -> Int
input :: String -> IO State -> IO State
input x state = do line <- getLine
st <- state
return $ Map.insert x (read line) st
get :: String -> IO State -> IO Int
get x state = do st <- state
return $ case Map.lookup x st of
Just i -> i
eval :: String -> Op -> String -> IO State -> IO Int
eval l op r state = do i <- get l state
j <- get r state
return $ op i j
main :: IO ()
main = do let state = return Map.empty
let state' = input "x" state
val <- eval "x" (+) "x" state'
putStrLn . show $ val
函数中的第二行main
模拟 的赋值x
,而第三行模拟二元+
运算符的求值。
我的问题是:我该如何解决这个问题,这样上面的代码只输入一次?我怀疑是IO
-wrapping 导致了问题,但是当我们处理 IO 时,我看不出有什么办法……?