Haskell出队的不变性

bvjxkvbb  于 2023-01-05  发布在  其他
关注(0)|答案(1)|浏览(115)

我有一个应用程序,需要处理队列中的一些项。有时删除项,有时添加新项。鉴于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

对于这段代码,我希望看到出队在每次迭代中增长1,但事实并非如此,这意味着结构保持不变。
如何在不同的迭代中使用出队?

toiithl6

toiithl61#

你可以使用递归。

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

还有更高级(也更复杂)的技术来对可变性建模,比如使用IORefST/State单子,但对于简单的情况,基本的递归定义就足够了。
请注意,您不能像尝试的那样“重新分配”:

let workQ = workQ'
putStrLn $ "Length " ++ (show len)
sleep 5

这定义了一个 new 变量workQ,它与上面定义的同名变量完全无关,新变量的作用域只有下面几行,在这些行中没有使用它,所以它是一个无用的定义。
你可以把这种重新定义想象成发生在C++中的事情:

{
   Dqueue workQ = ... ;
   stuff();
   if (blah) {
      Dqueue workQ = ... ;
      // this does not affect the outer variable
   }
}

定义一个变量与在外部作用域中定义的另一个变量同名被称为“隐藏”。GHC会警告这一点(如果你启用了警告),因为这通常是一个错误。

相关问题