Haskell有"变量"?或者,最简单的方法来读取配置数据?

时间:2016-06-12 05:19:27

标签: haskell immutability

我编写了带有硬编码配置变量的中型Haskell应用程序(如Google OAuth ClientId& ClientSecret)。既然我正在为生产部署准备应用程序,我需要将所有这些配置变量从源代码移到:(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将重新绑定,但我的编辑器立即开始显示警告&#34;绑定阴影现有绑定&#34;,表示Haskell正在创建一个新的绑定,而不是更改现有绑定。

所以,这里有两个问题:

  1. 首先,务实的。如何解决手头的问题,没有进入Reader monad,这可能涉及在我的应用程序中更改大量功能签名。
  2. 第二,面向学习的人。 Haskell具有不可变的,这是理解和赞赏的。它是否具有不可变的变量绑定?是不可能获得动态变量绑定,例如Common Lisp?
  3. 编辑:以下方法如何?

    以下方法怎么样?

    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
    

1 个答案:

答案 0 :(得分:4)

我认为您经常在代码库中依赖googleClientId等全局变量。

在进入“技术债务”路线之前,您可能想尝试并至少估算Reader方法的成本。无论如何,全局变量都是一种不好的做法,@ Casten提出了另一种重构方法。但既然你要求务实的帮助......

问题1:最快/最简单方式是使用皱眉unsafePerformIO。像这样:

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

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

问题2:人们不能在Haskell中“更新”变量。如果在嵌套范围中创建另一个具有相同名称的变量,则该绑定将遮蔽内部范围中的外部变量,从而保持外部绑定不变。这有点令人困惑,因此警告。