haskell - 从 IO Monad 设置配置参数 - 设计模式

标签 haskell configuration io

我希望我的问题是一个通用的问题,实际上我正在使用 wreq 更具体地使用 Web API 查询。 Web 服务请求一些不记名 <> token 授权,我设法发布了一个请求r = post (serveraddress ++ "/api/Integration/Login") (toJSON (AuthDataStruct "user" "xxxxxx"))我得到了回复 r我可以从中提取“token_type”和“access_token”

accessToken = r >>= (\ x -> return $ x ^. responseBody . key "access_token" . _String)
tokenType = r >>= (\ x -> return $ x ^. responseBody . key "token_type" . _String)
但这些数据是 IO 类型(IO 文本 - 准确地说),问题是需要这些数据来构建授权 header
authHeader :: IO Network.Wreq.Options
authHeader = do
     tk <- tokenType
     at <- accessToken
     let auth = AccessToken (unpack tk) (unpack at)
     return (opts auth)
opts token = defaults & header "Authorization" .~ [BI.packChars (tokenType token ++ " " ++ accessToken token)]然后用于对 Web 服务发出的每个请求:
webQueryGetProperties :: IO (Response Data.ByteString.Lazy.Internal.ByteString)
webQueryGetProperties = do`
     opt <- authHeader 
     let sql = GetDocument 1 ""  
     postWith opt (serveraddress ++ "/api/Integration/GetProperties") (toJSON sql)



webQueryGetDataValues etc...
不要太关注代码尝试按照我的推理,我想设置一个配置数据结构来存储 token 信息以避免运行所有IO只是为了得到我已经拥有的.. .(这是资源的浪费,不是DRYI) token 只需要在一段时间后更新。
理想的情况是有一个配置构建器,它使用从 IO 操作中提取的数据创建存储的 token 数据类型。如果我没有错的话,在 Haskell 中是不可能的(无法逃脱 monad),可能的解决方案是什么:
  • 将所有代码保存在同一个 IO monad 中,以便访问对授权 token 的所有过多请求?但是它是如何处理“纯度”的我在所有代码中都陷入了不纯的 IO
  • 使用 IORef?
  • 其他模式?

  • 在命令式语言中,您只需从结果中获取 token 数据并将其提供给构造函数,您就可以一劳永逸地设置“全局”配置。

    最佳答案

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

    webQueryGetProperties :: Options -> IO (Response ByteString)
    webQueryGetProperties o = postWith o (...) (...)
    
    是的,所有依赖于配置的东西,甚至是传递性的,都必须把它作为一个参数。
    然后,在顶层,您构建一次配置。
    main = do
        o <- authHeader
        webQueryGetProperties o
        webQueryGetDataValues o
        -- etc.
    
    有时候用起来很方便ReaderT为你传递争论。值得注意的是,这使得编写不需要参数的操作成为可能,而这种方式却忽略了它们实际上是在为您传递参数这一事实。
    webQueryGetProperties :: ReaderT Options IO (Response ByteString)
    webQueryGetProperties = do
        o <- ask
        liftIO (postWith o (...) (...))
    
    doesn'tNeedOptions :: MonadIO m => IO String
    doesn'tNeedOptions = liftIO $ do
        putStrLn "wow"
        getLine
    
    main = do
        o <- authHeader
        flip runReaderT o $ do
            webQueryGetProperties
            doesn'tNeedOptions -- configuration gets passed to this but ignored automatically
            webQueryGetDataValues
    
    实际上,在这种风格中,人们通常会编写更多的类多态性,所以
    webQueryGetProperties :: (MonadReader Options m, MonadIO m) => m (Response ByteString)
    -- implementation doesn't change
    
    如果您需要能够注意到 token 已过期并需要替换为不同的 token ,您可以升级到 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)
    

    关于haskell - 从 IO Monad 设置配置参数 - 设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65496635/

    相关文章:

    haskell - 使用 alex/happy 和 Cabal

    configuration - 如何在 dotnet-isolated (net5.0) azure 函数中使用 IOptions 模式进行配置

    c++ - I/O 流操纵器 - 内部调整域 - C++ 与 C

    java - 为什么用Java下载文件速度这么慢

    haskell - 通过模式匹配过滤列表

    haskell - 模板haskell范围之外的编译时间代码重写?

    haskell - 如何在 haskell 中使用合理的缩进初始化矩阵

    python - PyCharm自动更改脚本

    c# - 如何获取配置元素

    java - 为什么我的程序停止运行并且不返回错误?