我有一个应用程序需要处理队列上的一些项目。有时脱下物品,有时穿上新物品。鉴于 haskell 数据结构的不变性,我对如何实现这一点感到困惑。这是我的实验代码
module Main where
import Data.Dequeue as D
import Data.Time
import Control.Concurrent (threadDelay)
import Control.Monad (forever)
data ScheduledCall = ScheduledCall {
not_before :: UTCTime
, apiParameters :: String
}
sleep :: Int -> IO ()
sleep n = threadDelay (n * 1000 * 1000)
main :: IO ()
main = do
let workQ :: D.BankersDequeue ScheduledCall
workQ = D.empty
now <- getCurrentTime
forever $ do
let workQ' = D.pushBack workQ (ScheduledCall now "first")
-- possibly do something with the items
let len = length workQ'
let workQ = workQ'
putStrLn $ "Length " ++ (show len)
sleep 5
Run Code Online (Sandbox Code Playgroud)
使用这段代码,我希望看到出队在每次迭代中增加 1,但事实并非如此。这意味着结构保持不变。
如何通过不同的迭代使用出队?
您可以使用递归。
main = do
now <- getCurrentTime
let loop workQ = do
let workQ' = D.pushBack workQ (ScheduledCall now "first")
-- possibly do something with the items
let len = length workQ'
putStrLn $ "Length " ++ (show len)
sleep 5
loop workQ' -- recurse with the new queue
loop D.empty -- start the loop with an initially empty dqueue
Run Code Online (Sandbox Code Playgroud)
有更先进(和复杂)的技术来建模可变性,例如使用IORefs 或ST/ Statemonad,但对于简单的情况,基本的递归定义就足够了。
请注意,您不能像尝试那样“重新分配”:
let workQ = workQ'
putStrLn $ "Length " ++ (show len)
sleep 5
Run Code Online (Sandbox Code Playgroud)
这定义了一个新变量workQ,该变量与上面定义的同名的其他变量完全无关。新变量的作用域仅是以下几行,其中未使用它,因此它是一个无用的定义。
您可以将这种重新定义视为 C++ 中发生的情况:
main = do
now <- getCurrentTime
let loop workQ = do
let workQ' = D.pushBack workQ (ScheduledCall now "first")
-- possibly do something with the items
let len = length workQ'
putStrLn $ "Length " ++ (show len)
sleep 5
loop workQ' -- recurse with the new queue
loop D.empty -- start the loop with an initially empty dqueue
Run Code Online (Sandbox Code Playgroud)
定义一个与外部作用域中定义的另一个变量同名的变量称为“遮蔽”。GHC 会对此发出警告(如果您启用警告),因为这通常是一个错误。