Cli*_*ton 3 state haskell acid yesod
我正在阅读Toy URL Shortener的代码.然而,有一些重要的部分我无法理解.
它具有以下代码:
data URLShort = URLShort { state :: AcidState URLStore }
Run Code Online (Sandbox Code Playgroud)
出于测试目的,我在自己的应用程序中写了这样的东西:
data MyApp = MyApp { state :: Int }
Run Code Online (Sandbox Code Playgroud)
然后我可以通过改变来编译
main = warpDebug 3000 MyApp
Run Code Online (Sandbox Code Playgroud)
至
main = warpDebug 3000 (MyApp 42)
Run Code Online (Sandbox Code Playgroud)
然后,我可以通过执行操作来读取处理程序中的状态
mystate <- fmap state getYesod
Run Code Online (Sandbox Code Playgroud)
受到acid <- fmap state getYesod
文章的启发.但是,我不知道怎么写.
我也尝试过:
data MyApp = MyApp { state :: State Int Int }
Run Code Online (Sandbox Code Playgroud)
但我对此并没有做多少.
我试图AcidState
通过做一些简单的类似例子来弄清楚它是如何工作的,并且认为既然AcidState
将所有内容保存在内存中,我应该能够做同样的事情吗?
对这里发生的事情的任何形式的一般性解释,以及也许我如何忽略这一点都将非常感激.
的AcidState a
数据类型不是一个不变的值一路向下; 它内部包含对可变数据的引用.在这种情况下,Yesod-land中存储的内容只是对此数据的不可变引用.更新状态时,实际上并不更新基础数据类型中的值,而是更新它指向的内存.
Haskell世界中的每个值都是不可变的.但是,Haskell领域之外的很多东西都不是一成不变的; 例如,当您这样做时putStrLn
,终端会改变其显示以显示新内容.该putStrLn
行动本身是不可变的纯价值,但它描述了如何执行涉及突变的作用.
还有其他功能也会产生执行突变的动作; 如果这样做ref <- newIORef 0
,您将获得一个描述创建可变内存单元的操作的值.如果您这样做modifyIORef ref (+1)
,您将获得一个值,该值描述一个增加该单元格中的值的操作1
.该ref
值是纯值,它只是对可变单元格的引用.代码也纯粹是功能性的,因为每个部分只描述一个动作; 在Haskell程序中没有任何可变性.
这是如何AcidState
实现其状态:通过使用管理Haskell世界之外的状态的系统.这并不像C语言这样具有完全可变性"一样糟糕",因为在Haskell中,你可以用monad的力量来控制可变性.使用AcidState
是非常安全的,并不涉及unsafePerformIO
我所知的使用.
用AcidState
在这种情况下,可以使用openAcidState emptyStore
在IO
单子创建一个新的酸状态(即线是描述打开一个新的酸状态的IO动作的值).您createCheckpointAndClose
可以选择安全地将酸状态保存到磁盘.最后,使用该update'
函数来改变酸状态的内容.
要使用IORef
s(最简单的可变状态形式,可能是ST
monad)创建一个"小状态" ,首先要将这样的字段添加到基础数据类型中:
data VisitorCounter = VisitorCounter { visitorCounter :: IORef Int }
Run Code Online (Sandbox Code Playgroud)
然后你做:
main = do
counter <- newIORef 0
warpDebug 3000 (VisitorCounter counter)
Run Code Online (Sandbox Code Playgroud)
在处理程序中,您可以像这样修改计数器:
counter <- fmap visitorCounter getYesod
modifyIORef counter (+1)
count <- readIORef counter
-- ... display the count or something
Run Code Online (Sandbox Code Playgroud)
注意对称性AcidState
.
对于站点计数器,我实际上建议使用TVar
s而不是IORef
s,因为多个客户端可能同时修改变量.然而,TVar
s 的接口非常相似.
来自问题作者的跟进问题?
我已经放入{ visitorCounter :: TVar Int }
了我的基础类型,以及处理程序中的以下代码:
counter <- fmap visitorCounter getYesod
count <- readTVar counter
Run Code Online (Sandbox Code Playgroud)
第一行编译正常,但第二行抛出此错误:
Run Code Online (Sandbox Code Playgroud)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
我怎么能解决这个问题?
归档时间: |
|
查看次数: |
889 次 |
最近记录: |