3

我正在阅读Toy URL Shortener的代码。但是,有些重要的部分我无法理解。

它有以下代码:

data URLShort = URLShort { state :: AcidState URLStore }

出于测试目的,我在自己的应用程序中写了这样的内容:

data MyApp = MyApp { state :: Int }

然后我可以通过改变来编译

main = warpDebug 3000 MyApp

main = warpDebug 3000 (MyApp 42)

然后我可以通过执行来读取处理程序中的状态

mystate <- fmap state getYesod 

灵感来自acid <- fmap state getYesod于文章。但是,我不知道怎么写。

我也尝试过这样做:

data MyApp = MyApp { state :: State Int Int }

但我并没有走得太远。

AcidState我试图通过做一些简单的类似示例来弄清楚它是如何工作的,我想既然AcidState将所有内容都保存在内存中,我应该也可以这样做吗?

对这里发生的事情的任何一般解释,以及我如何遗漏这一点,将不胜感激。

4

1 回答 1

7

AcidState a数据类型一直不是不可变的值;它在内部包含对可变数据的引用。在这种情况下,存储在 Yesod-land 中的内容只是对该数据的不可变引用。更新状态时,实际上并没有更新基础数据类型中的值,而是更新它指向的内存。

Haskell 世界中的每一个值都是不可变的。然而,Haskell 领域之外的很多东西都不是一成不变的。例如,当您这样做时putStrLn,终端会改变其显示以显示新内容。putStrLn动作本身是不可变的纯值,但它描述如何执行涉及突变的动作。

还有其他函数也产生执行突变的动作。如果你这样做ref <- newIORef 0,你会得到一个描述创建可变记忆单元的动作的值。如果您这样做modifyIORef ref (+1),您将获得一个值,该值描述了将该单元格中的值增加 1 的操作1refvalue 是一个纯 value,它只是对可变单元格的引用。代码也是纯函数式的,因为每一段只描述一个动作;Haskell 程序中没有什么是可变的。

这是AcidState实现其状态的方式:通过使用在 Haskell 世界之外管理状态的系统。这并不像在 C 等语言中那样具有完全可变性“那么糟糕”,因为在 Haskell 中,您可以使用 monad 的力量来控制可变性。使用是完全安全的,据我所知AcidState不涉及使用。unsafePerformIO

AcidState这种情况下,您openAcidState emptyStoreIOmonad 中使用来创建新的酸状态(该行是描述打开新酸状态的 IO 操作的值)。您createCheckpointAndClose可以选择将酸状态安全地保存到磁盘。最后,您使用该update'函数来改变酸性状态的内容。

要使用 s 自己创建一个“小状态” IORef(可变状态的最简单形式,可能除了STmonad),您首先将这样的字段添加到您的基础数据类型中:

data VisitorCounter = VisitorCounter { visitorCounter :: IORef Int }

然后你做:

main = do
  counter <- newIORef 0
  warpDebug 3000 (VisitorCounter counter)

在处理程序中,您可以像这样修改计数器:

counter <- fmap visitorCounter getYesod
modifyIORef counter (+1)
count <- readIORef counter
-- ... display the count or something

注意 的对称性AcidState

对于站点计数器,我实际上建议使用TVars而不是IORefs,因为多个客户端可能同时修改变量。然而,与 s 的接口TVar非常相似。


问题作者的后续问题?

我已经放置{ visitorCounter :: TVar Int }在我的基础类型中,并且在处理程序中放置了以下代码:

counter <- fmap visitorCounter getYesod
count <- readTVar counter

第一行编译正常,但第二行抛出此错误:

Couldn't match expected type `GHandler sub0 Middleware t0'
            with actual type `STM a0'
In the return type of a call of `readTVar'
In a stmt of a 'do' expression: count <- readTVar counter

我该如何解决这个问题?

于 2012-04-04T12:49:05.833 回答