Joh*_*han 2 haskell shared-state ioref
我正在努力学习Haskell,我正在玩IORef,我试图保存并查找记录.我的代码看起来像这样(注意我在这个例子中选择了"String"作为IORef类型只是为了方便和简介,在我的实际代码中我正在使用记录.而且还忽略我使用的是Set而不是一张地图,我会改变一下):
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"
Run Code Online (Sandbox Code Playgroud)
我想要实现的是共享两个函数调用之间的状态(Set),以便findStringInState可以返回String我刚刚插入Set中的状态.但是当我运行该doStuff函数时,我得到了这个:
*MyTest> doStuff
### saved: fromList ["string1"]
Looking for string1 in: fromList []
Nothing
Run Code Online (Sandbox Code Playgroud)
我可能误解了一些东西,因为我认为IORef确实应该是我州的容器.
似乎你IO IORefState与IORefState(没有IO)混淆,更普遍的是,IO a与a.
在您的情况下,值的作用IO IORefState是动作 newIORef empty,它表示" IORef从头开始创建新动作的动作".
相比之下,IORefState(没有IO)是您应该在使用它的函数(,和)之间共享的正确的原始对象.
然后,这两个和单独呼叫,即,它们中的每一个创建不同对象,它不能由其他的影响.saveStringToStatefindStringInStatesaveStringToStatefindStringInStatenewIORef emptyIORefState
要修复,您必须在函数中调用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"
Run Code Online (Sandbox Code Playgroud)
在我看来,IO awith 之间的区别a类似于"一个函数对象返回一个键入的值a(带有一些副作用)"和"只是一个原始值类型为a"在其他编程语言中的区别.