【问题标题】:IORef still refers to the old value after updateIORef 更新后仍然引用旧值
【发布时间】:2017-08-21 11:20:58
【问题描述】:

背景

我是一名计划者,开始学习 Haskell。我正在尝试在 C 中实现一个 Scheme 解释器,遵循 SICP 的chapter 4。事实证明,直接用 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

语法高亮版本:

感谢您的帮助!

【问题讨论】:

  • global 用新的IORef 创建新的SCM。您应该重新组织循环,其中global 将执行一次。

标签: haskell io scheme ioref


【解决方案1】:

我们可以将您的示例缩减为 main = (global &gt;&gt;= loop) &gt;&gt; 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。因此,您不会得到预期的行为。

解决方案很简单。明确创建您的globalloop

main = do
  global <- createSCM
  let loop = do
         ...
         loop
  loop

【讨论】:

  • 谢谢,所以我的误解是将其视为全球性的。但实际上,它的行为更像是一个构造函数,对吧?
  • @AlexVong 对。您可以将任何IO a 视为一个action,如果执行该操作将产生a。例如,readLine :: IO String 会在你执行它时给你一个String,但你不希望readLine 每次调用都返回相同的字符串(这取决于用户的输入)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-08
  • 1970-01-01
  • 2019-06-28
  • 1970-01-01
  • 2013-12-28
  • 1970-01-01
相关资源
最近更新 更多