Haskell 从IO Monad设计模式设置配置参数

Haskell 从IO Monad设计模式设置配置参数,haskell,configuration,io,Haskell,Configuration,Io,我希望我的问题是一个一般性的问题,实际上我正在更具体地使用wreq处理web API查询。Web服务请求一些承载令牌授权,我设法发布一个请求 r=post(serveraddress++“/api/Integration/Login”)(toJSON(AuthDataStruct“user”“xxxxxx”) 然后我得到一个响应r,从中我可以提取一个“令牌类型”和一个“访问令牌” 但是这些数据是IO类型的(确切地说是IO文本),需要这些数据来构建授权头 authHeader :: IO Netw

我希望我的问题是一个一般性的问题,实际上我正在更具体地使用wreq处理web API查询。Web服务请求一些承载令牌授权,我设法发布一个请求

r=post(serveraddress++“/api/Integration/Login”)(toJSON(AuthDataStruct“user”“xxxxxx”)

然后我得到一个响应
r
,从中我可以提取一个“令牌类型”和一个“访问令牌”

但是这些数据是IO类型的(确切地说是IO文本),需要这些数据来构建授权头

authHeader :: IO Network.Wreq.Options
authHeader = do
     tk <- tokenType
     at <- accessToken
     let auth = AccessToken (unpack tk) (unpack at)
     return (opts auth)
不要太注意代码尝试按照我的推理,我想建立一个配置数据结构来存储令牌信息,以避免运行所有IO只是为了获得我已经拥有的。。。(这是对资源的浪费,而不是DRYI)代币只需要在一段时间后更新即可。 理想情况是有一个配置生成器,它使用从IO操作提取的数据创建一个存储的令牌数据类型。如果我没有错,在Haskell中是不可能的(无法逃脱单子),可能的解决方案是什么:

  • 将所有代码保存在同一IO monad中,以便能够访问授权令牌的所有过多请求?但是它是如何处理“纯净”的呢?我在所有代码中都被困在一个不纯净的IO中
  • 使用IORef
  • 其他模式

在命令式语言中,您只需从结果中获取令牌数据并将其交给构造函数,就可以一次性设置“全局”配置。

低技术模式就是简单地接受您的配置作为参数

webQueryGetProperties :: Options -> IO (Response ByteString)
webQueryGetProperties o = postWith o (...) (...)
是的,所有依赖于配置的东西,即使是传递的,都必须将其作为参数

webQueryGetProperties :: Options -> IO (Response ByteString)
webQueryGetProperties o = postWith o (...) (...)
然后,在顶层,构建一次配置

main = do
    o <- authHeader
    webQueryGetProperties o
    webQueryGetDataValues o
    -- etc.
实际上,在这种风格中,人们通常会编写更多的类多态性,所以

webQueryGetProperties :: (MonadReader Options m, MonadIO m) => m (Response ByteString)
-- implementation doesn't change
如果您需要能够注意到令牌已过期并且需要用其他令牌替换,则可以升级到
StateT

webQueryGetProperties :: (MonadState Options m, MonadIO m) => m (Response ByteString)
webQueryGetProperties = do
    o <- get
    liftIO (postWith o (...) (...))

checkAndRenew :: (MonadState Options m, MonadIO m) => m ()
checkAndRenew = do
    renewp <- gets needsToBeRenewed
    when renewp (authHeader >>= put)
webQueryGetProperties::(MonadState选项m,MonadIO m)=>m(Response ByteString)
webQueryGetProperties=do
o m()
checkAndRenew=do
续订>=put)

非常感谢,我也在考虑将代码重构为mtl(ReaderT)-但为了避免多次查询请求令牌,我需要保留在一个函数中(即在一个“do评估”中)-实际上,我的配置不是“存储”在程序中,而是在远程服务器上,只是“被询问”根据程序。@user3680029我想我不明白这个问题。在向远程服务器请求配置后,如果不是“存储”并使用它,您希望您的程序如何处理配置?您没有误解-我只是在问自己,是否有推荐的方法将其存储在“非IO”变量中-例如使用函数:IO Response->IO()作为一种副作用,它将在引擎盖下填充一个“globish”类型的变量。@user3680029否。
webQueryGetProperties :: (MonadReader Options m, MonadIO m) => m (Response ByteString)
-- implementation doesn't change
webQueryGetProperties :: (MonadState Options m, MonadIO m) => m (Response ByteString)
webQueryGetProperties = do
    o <- get
    liftIO (postWith o (...) (...))

checkAndRenew :: (MonadState Options m, MonadIO m) => m ()
checkAndRenew = do
    renewp <- gets needsToBeRenewed
    when renewp (authHeader >>= put)