在使用IO时,如何在Haskell中的两个函数调用之间共享IOREF状态



我正在尝试学习Haskell,并且正在与Ioref一起玩,我尝试保存并查找记录。我的代码看起来像这样(请注意,在此示例中,我选择"字符串"为IOREF类型,仅用于说明和短暂性,在我的实际代码中,我正在使用记录。也忽略我正在使用集合在地图上,我将更改):

module MyTest where
import           Data.IORef
import           Data.Set
import           Data.Foldable          (find)
type State = (Set String)
type IORefState = IORef State
saveStringToState :: IO IORefState -> String -> IO String
saveStringToState stateIO string = do
  state <- stateIO
  atomicModifyIORef
    state
    (oldStrings ->
       let updatedStrings = insert string oldStrings
       in (updatedStrings, updatedStrings))
  stringsState <- readIORef state :: IO State
  putStrLn ("### saved: " ++ show stringsState)
  return string
findStringInState :: IO IORefState -> String -> IO (Maybe String)
findStringInState stateIO soughtString = do
  state <- stateIO :: IO IORefState
  strings <- readIORef state :: IO State
  putStrLn ("Looking for " ++ soughtString ++ " in: " ++ show strings)
  return $ find (== soughtString) strings
doStuff =
  let stateIO = newIORef empty
  in do saveStringToState stateIO "string1"
        findStringInState stateIO "string1"

我要实现的是在两个函数调用之间共享状态(集合),以便findStringInState可以返回我刚刚插入集合中的String。但是当我运行doStuff功能时,我会得到:

*MyTest> doStuff
### saved: fromList ["string1"]
Looking for string1 in: fromList []
Nothing

我可能误解了一些东西,因为我认为IOREF确实应该是我州的容器。

  1. 为什么这不起作用?
  2. 我该怎么做才能使它起作用?

似乎您将 IO IORefStateIORefState(无IO)混淆了,更普遍地, IO aa

在您的情况下, IO IORefState的值是 newIORef empty,它代表"从头开始创建新的新IORef的动作"。
相比之下, IORefState(无IO)是正确的, raw对象您应该在使用它的功能中共享(saveStringToStatefindStringInState)。
然后,saveStringToStatefindStringInState单独调用newIORef empty,即它们都创建一个不同的IORefState对象,该对象不能受到另一个对象。

要修复,您必须在doStuff中调用newIORef empty(使用<-IO操作),并共享由newIORef empty而不是IO IORefState创建的IORefState

  saveStringToState :: IORefState -> String -> IO String
  ...
  findStringInState :: IORefState -> String -> IO (Maybe String)
  ...
  let stateIO = newIORef empty
  in do ioRef <- stateIO
        saveStringToState ioRef "string1"
        findStringInState ioRef "string1"
  -- Or, more simply:
  do ioRef <- newIORef empty
     saveStringToState ioRef "string1"
     findStringInState ioRef "string1"

我认为,使用aIO a之间的差异类似于"返回为a键入值的函数对象(具有副作用)(具有某些副作用)"one_answers"仅在另一个中键入a的原始值"之间的差异。编程语言。

最新更新