我正在尝试学习Haskell,并且正在尝试使用IORef来保存和查找记录。我的code看起来像这样(请注意,在本示例中,出于方便和简明的考虑,我已选择“ String”作为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"
我要实现的是在两个函数调用之间共享状态(Set),以便
findStringInState
可以返回我刚刚插入Set中的String
。但是当我运行doStuff
函数时,我得到了:*MyTest> doStuff
### saved: fromList ["string1"]
Looking for string1 in: fromList []
Nothing
自从我认为IORef应该确实是我所在州的容器以来,我可能误解了一些东西。
为什么这不起作用?
我该怎么做才能使其正常工作?
最佳答案
似乎您将IO IORefState
与IORefState
(没有IO
)混淆了,更普遍的是,将IO a
与a
混淆了。
在您的情况下,IO IORefState
的值是操作newIORef empty
,它表示“从头开始创建新的新IORef
的操作”。
相比之下,IORefState
(没有IO
)是您应该在使用它的功能(saveStringToState
和findStringInState
)之间共享的正确的原始对象。
然后,saveStringToState
和findStringInState
分别调用newIORef empty
,即它们各自创建一个不同的IORefState
对象,而彼此不受此对象的影响。
要解决此问题,必须在newIORef empty
函数中调用IO
(作为使用<-
的doStuff
动作)并共享由IORefState
而不是newIORef empty
创建的IO 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"
在我看来,
IO a
与a
的区别类似于“返回一个键入为a
的值(具有某些副作用)的函数对象”和“只是一个键入为”在其他编程语言中。