我正在努力学习Haskell,我正在玩IORef,我试图保存并查找记录。我的code看起来像这样(注意我在这个例子中选择了“String”作为IORef类型只是为了方便和简介,在我的实际代码中我正在使用记录。而且我也忽略了我使用Set而不是Map,我会改变那个):
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确实应该是我州的容器。
答案 0 :(得分:6)
似乎您将IO IORefState
与IORefState
(没有IO
)混为一谈,更常见的是,IO a
与a
混淆。
在您的情况下,IO IORefState
的值操作 newIORef empty
,表示“从头开始创建全新IORef
的操作”。
相比之下,IORefState
(没有IO
)是正确的原始对象,您应该在使用它的函数之间共享它(saveStringToState
和{{1 }})。
然后,findStringInState
和saveStringToState
分别调用findStringInState
,即每个newIORef empty
创建一个不同的IORefState
对象,不会受到另一个的影响。
要解决此问题,您必须在newIORef empty
函数中调用IO
(使用<-
} doStuff
操作)并共享由{{1}创建的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
”的原始值。