在使用IO时,如何在Haskell中的两个函数调用之间共享IORef状态?
我正在尝试学习Haskell,并尝试使用IORef来保存和查找记录。我的代码是这样的(请注意,我在本例中选择“String”作为IORef类型只是为了方便和简洁,在我的实际代码中,我使用的是一个记录。同时忽略我使用的是集合而不是映射,我将对此进行更改): 我可能误解了一些东西,因为我认为IORef确实应该是我所在州的容器在使用IO时,如何在Haskell中的两个函数调用之间共享IORef状态?,haskell,shared-state,ioref,Haskell,Shared State,Ioref,我正在尝试学习Haskell,并尝试使用IORef来保存和查找记录。我的代码是这样的(请注意,我在本例中选择“String”作为IORef类型只是为了方便和简洁,在我的实际代码中,我使用的是一个记录。同时忽略我使用的是集合而不是映射,我将对此进行更改): 我可能误解了一些东西,因为我认为IORef确实应该是我所在州的容器 为什么这不起作用 我能做些什么使它工作 似乎您将IO IORefState与IORefState(无IO)混淆,更一般地说,IO a与a 在您的情况下,IO IORefStat
似乎您将
IO IORefState
与IORefState
(无IO
)混淆,更一般地说,IO a
与a
在您的情况下,IO IORefState
的值是动作newiorefempty
,它表示“从头开始创建新的IORef
的动作”。相比之下,
IORefState
(不带IO
)是正确的原始对象,您应该在使用它的函数之间共享它(saveStringToState
,和findStringInState
)。然后,
saveStringToState
和findStringInState
分别调用newiorefempty
,即它们各自创建一个不同的IORefState
对象,而另一个对象不会影响该对象
要修复此问题,必须使用String->IO String调用newiorefempty
(作为IO
操作)
...
findStringInState::IORefState->String->IO(可能是字符串)
...
让stateIO=newIORef为空
伊洛夫酒店
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"
*MyTest> doStuff
### saved: fromList ["string1"]
Looking for string1 in: fromList []
Nothing
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"