从静态配置迁移到动态配置

时间:2015-05-09 12:55:03

标签: haskell configuration-files

我正在开发一个haskell项目,其中的设置当前位于名为Setting.hs的文件中,因此在编译期间会对它们进行检查,并且可以全局访问。

但是,由于这有点太静态,我正在考虑在运行时读取配置。代码库是巨大的,似乎通过设置是相当大的努力,例如作为整个程序流程的参数,因为它们可以从任何地方任意访问。

是否有任何设计模式,库甚至ghc扩展可以在不重构整个代码的情况下提供帮助?

2 个答案:

答案 0 :(得分:4)

感谢您的提示!我想出了一个最小的例子,它展示了我将如何使用reflection包:

{-# LANGUAGE Rank2Types, FlexibleContexts, UndecidableInstances #-}

import Data.Reflection

data GlobalConfig = MkGlobalConfig {
    getVal1 :: Int
  , getVal2 :: Double
  , getVal3 :: String
}

main :: IO ()
main = do
  let config = MkGlobalConfig 1 2.0 "test"
  -- initialize the program flow via 'give'
  print $ give config (doSomething 2)
  -- this works too, the type is properly inferred
  print $ give config (3 + 3)
  -- and this as well
  print $ give config (addInt 7 3)

-- We need the Given constraint, because we call 'somethingElse', which finally
-- calls 'given' to retrieve the configuration. So it has to be propagated up
-- the program flow.
doSomething :: (Given GlobalConfig) => Int -> Int
doSomething = somethingElse "abc"

-- since we call 'given' inside the function to retrieve the configuration,
-- we need the Given constraint
somethingElse :: (Given GlobalConfig) => String -> Int -> Int
somethingElse str x
  | str == "something"      = x + getVal1 given
  | getVal3 given == "test" = 0 + getVal1 given
  | otherwise               = round (fromIntegral x * getVal2 given)

-- no need for Given constraint here, since this does not use 'given'
-- or any other functions that would
addInt :: Int -> Int -> Int
addInt = (+)

Given类更易于使用,非常适合全局配置模型。所有不使用given(获取值)的函数似乎都不需要类约束。这意味着我只需要更改实际访问全局配置的函数。

这就是我要找的东西。

答案 1 :(得分:0)

你在问什么,如果有可能会破坏参照透明度,至少对于纯函数来说(纯函数结果可能依赖于某些全局变量,但不能在配置文件中取决于它)?

通常人们通过Monad隐式地将配置作为数据传递来避免这种情况。或者(如果您愿意稍微重构一下代码),您可以使用implicit parameter extenson,理论上已经解决了这类问题,但实际上并没有真正起作用。 但是,如果您确实需要,可以使用unsafePerformIOioRef来使top level mutable state变得脏兮兮的皱眉。您需要一个顶级可变状态,因为您需要能够在加载初始配置时修改“mutate”。

然后你会得到类似的东西:

myGlobalVar :: IORef Int
{-# NOINLINE myGlobalVar #-}
myGlobalVar = unsafePerformIO (newIORef 17)