我是一名开始学习Haskell的Schemer。我试图在SICP的chapter 4之后用C实现一个Scheme解释器。事实证明直接用C编程太难了。所以我决定先在Haskell中进行原型设计。在Write Yourself a Scheme in 48 Hours的帮助下,我实现了除变量,闭包和环境之外的所有内容。
在IORef
的调用之间,对main
的修改不会持续存在。我希望程序打印(False)(True)(True)(True) ...但实际上它打印(False)(True)(False)(True)(False) )(真) ......
代码的精简版:
import Data.IORef
data SCM = Environment (IORef Bool) SCM | Empty'Environment
global :: IO SCM
global = Environment <$> newIORef False <*> pure Empty'Environment
print'' :: SCM -> IO ()
print'' ls =
case ls of
Empty'Environment -> pure ()
Environment first rest -> readIORef first >>= putStr . show >> print'' rest
print' :: SCM -> IO ()
print' ls = putStr "(" *> print'' ls *> putStrLn ")"
main :: IO ()
main = global >>=
\ls -> case ls of
Empty'Environment -> pure ()
Environment first _ -> print' ls *>
modifyIORef first (const True) *>
print' ls *>
main
感谢您的帮助!
答案 0 :(得分:7)
我们可以将您的示例缩减到main = (global >>= loop) >> main
。问题是global
不是一个全局变量,而是一个IO SCM
,一个将创建全局值的动作。我们重命名一下:
createSCM :: IO SCM
createSCM = Environment <$> newIORef False <*> pure Empty'Environment
现在这个名字更接近真相。每次调用该函数时,我们都会创建一个新的SCM
。所以你的程序是这样的:
main = (createSCM >>= loop) >> main
= (createSCM >>= loop) >> (createSCM >>= loop) >> main
= (createSCM >>= loop) >> (createSCM >>= loop) >> ...
正如您所见,我们一直在创建新的SCM
。因此,您无法获得预期的行为。
解决方案很简单。明确地创建您的global
和loop
:
main = do
global <- createSCM
let loop = do
...
loop
loop