将结果缓存一段时间并返回缓存值

时间:2013-10-28 02:47:35

标签: haskell

我想做以下事情:方法getSessionToken

  • 如果“cachedSessionToken”已过时(超过1小时前发布),请向服务器发出请求

  • 一旦向服务器发出请求,它会将结果保存为“variable”,然后在调用getSessionToken时将其返回

因此,想法是缓存结果并在需要时返回,否则首先向服务器getSessionTokenRemote发出请求,缓存它并且仅在返回结果之后。我对getSessionTokenRemote的确切实现不感兴趣,但是,它可能是这样的:

getSessionTokenRemote :: IO String
-- or just
getSessionTokenRemote :: String
无论最合适的是什么。

我想知道,我怎么用纯函数语言如Haskell来做到这一点?

2 个答案:

答案 0 :(得分:5)

如果您希望getSessionTokenRemote写入变量,则必须将其传递给一个变量,例如给它一个类似的类型:

type CacheInfo = {- you've got to fill this bit in -}
getSessionTokenRemote :: IORef CacheInfo -> IO String

一旦你选择了这样的类型,实现就不会太难了。

另一种方法是,如果你进入实现隐藏,就是写一个产生getSessionTokenRemote值的值。假设上面的类型的内部实现和一些空的缓存值emptyCacheInfo,可以这样做:

getGetSessionTokenRemote :: IO (IO String)
getGetSessionTokenRemote = getSessionTokenRemote <$> newIORef emptyCacheInfo

这是一个IO操作,在执行时会产生一个带有新缓存的会话令牌获取操作。

答案 1 :(得分:3)

Haskell确实有状态变量,但它们是“被管理的”。它们不可避免地在某些monad中运行,你必须明确地读/写它们。 IORefMVarTVar和朋友都是'管理参考'(我第一次听到Clojure社区中使用的术语)。

这是一个可怕的简化示例,说明如何使用ref类型来设置内容。

import Data.IORef
import Network.HTTP

data SessionToken = SessionToken {
    _timeHours :: Int
  , _token     :: String
  }

getSessionToken :: IORef SessionToken -> IO String
getSessionToken cacheRef = do
  cachedToken <- readIORef cacheRef
  if   _timeHours cachedToken > 1
  then do 
    newToken <- getSessionTokenRemote
    writeIORef cacheRef newToken
    return $ _token newToken
  else return $ _token cachedToken

getSessionTokenRemote :: IO SessionToken
getSessionTokenRemote = do
  tokenRequest <- simpleHTTP $ getRequest "http://jtobin.ca/sample_token.txt"
  token        <- getResponseBody tokenRequest
  return $ SessionToken 0 token

main :: IO ()
main = do
  tokenRef <- newIORef $ SessionToken 0 "my token"
  getSessionToken tokenRef >>= putStrLn

  writeIORef tokenRef $ SessionToken 2 "my token"
  getSessionToken tokenRef >>= putStrLn