哈斯克尔有"variables"吗?或者,读取配置数据的最简单方法?



我已经用硬编码的配置变量(如Google OAuth ClientId和ClientSecret)编写了我的中型Haskell应用程序。现在我正在为生产部署准备应用程序,我需要将所有这些配置变量从源代码中移到:(a)环境变量,或(b)纯文本配置文件。

以下是目前代码的样子:

googleClientId :: T.Text
googleClientId = "redacted"
googleClientSecret :: T.Text
googleClientSecret = "redacted"
generateOAuthUserCode :: IO (OAuthCodeResponse)
generateOAuthUserCode = do
r <- asJSON =<< post "https://accounts.google.com/o/oauth2/device/code" ["client_id" := googleClientId, "scope" := ("email profile" :: T.Text)]
return $ r ^. responseBody

从环境变量(或配置文件)中获取googleClientIdgoogleClientSecret的最快/最简单方法是什么?我尝试了以下方法:

googleClientId :: T.Text
googleClientId = undefined
googleClientSecret :: T.Text
googleClientSecret = undefined
main :: IO()
main = do 
googleClientId <- getEnv "GOOGLE_CLIENT_ID"
googleClientSecret <- getENV "GOOGLE_CLIENT_SECRET"
-- Start the main app, which internally will call generateOAuthUserCode at some point.

我们的预期是全局googleClientIdgoogleClientSecret将被重新绑定,但我的编辑器立即开始显示一条警告,即"绑定遮蔽了现有绑定",这表明Haskell正在创建一个新绑定,而不是更改现有绑定。

所以,这里有两个问题:

  1. 首先是务实的。如何解决手头的问题,而不进入Reader monad,这可能涉及在我的应用程序中更改许多函数签名
  2. 第二,以学习为导向。Haskell有不可变的,这是可以理解和欣赏的。它甚至有不可变的变量绑定吗?难道不可能像Common Lisp中那样获得动态变量绑定吗

编辑:以下方法如何?

下面的方法怎么样?

outerFunc :: String -> String -> IO ()
outerFunc googleClientId googleClientSecret = do
-- more code comes here
where
generateOAuthUserCode :: IO (OAuthCodeResponse)
generateOAuthUserCode = do
r <- asJSON =<< post "https://accounts.google.com/o/oauth2/device/code" ["client_id" := googleClientId, "scope" := ("email profile" :: T.Text)]
return $ r ^. responseBody
-- more functions depending upon the config variables

我假设在代码库中经常依赖像googleClientId这样的全局变量。

在走"技术债务"路线之前,您可能需要尝试并至少估计Reader方法的成本。无论如何,全局变量是一种糟糕的做法,@Carsten提出了另一种重构方法。但既然你在寻求务实的帮助

问题1:最快/最简单的方法是使用不受欢迎的unsafePerformIO。像这样:

googleClientId = unsafePerformIO $ getEnv "GOOGLE_CLIENT_ID"
main = putStrLn googleClientId

这基本上允许您忽略IO的安全性,并将所需的值放入全局变量中,就像它是一个普通字符串一样。请注意,如果环境变量不存在,getEnv将崩溃

问题2:不能在Haskell中"更新"变量。如果在嵌套作用域中创建另一个同名变量,则该绑定将在内部作用域中覆盖外部变量,使外部绑定保持不变。这有点令人困惑,因此发出了警告。

最新更新