我正在使用haskell项目,其中的设置当前位于名为Setting.hs
的文件中,因此它们在编译期间被检查并且可以在全局访问。从静态配置移动到动态配置
但是,由于这有点过于静态,我正考虑在运行时读取配置。代码库是巨大的,看起来要通过设置是相当大的努力,例如作为整个程序流程的一个参数,因为它们可以从任何地方随意访问。
是否有任何设计模式,库或ghc扩展可以在不重构整个代码的情况下提供帮助?
我正在使用haskell项目,其中的设置当前位于名为Setting.hs
的文件中,因此它们在编译期间被检查并且可以在全局访问。从静态配置移动到动态配置
但是,由于这有点过于静态,我正考虑在运行时读取配置。代码库是巨大的,看起来要通过设置是相当大的努力,例如作为整个程序流程的一个参数,因为它们可以从任何地方随意访问。
是否有任何设计模式,库或ghc扩展可以在不重构整个代码的情况下提供帮助?
你在问什么,如果可能会破坏参照透明度,至少对于纯函数(纯函数结果可能取决于某些全局变量,但不能在配置文件上不能))?
通常人们通过Monad隐式传递配置作为数据来避免这种情况。或者(如果你很乐意重构你的代码),你可以使用implicit parameter extenson,这在理论上已经被用来解决这种类型的问题,但实际上并不真正起作用。 但是,如果你真的需要,你可以使用unsafePerformIO
和ioRef
有一个top level mutable state这是肮脏和皱眉咆哮。你需要一个最高级别的可变状态,因为当你加载它时,你需要修改“mutate”你的初始配置。
然后你得到这样的事情:
myGlobalVar :: IORef Int
{-# NOINLINE myGlobalVar #-}
myGlobalVar = unsafePerformIO (newIORef 17)
谢谢你的提示!我想出了一个小例子,显示我怎么会去了解它与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
(获取值)的函数似乎不需要类约束。这意味着我只需要改变实际访问全局配置的功能。
这就是我一直在寻找的。
隐式参数或读者monad是常用选项,但它们确实需要一些更改。 – chi
看看[隐式配置 - 或者,类型类反映类型的值](http://okmij.org/ftp/Haskell/types.html#Prepose),如果它可以帮助。 –
在@PetrPudlák注释中进行了扩展,隐式配置的实现可以在'reflection'包中找到。在repo的examples文件夹中,有一个看起来很相关的“类似读者”的例子:https://github.com/ekmett/reflection/blob/master/examples/ReaderLike.hs。另请参阅此SO回答以获取使用示例:http://stackoverflow.com/a/29929718/1364288 – danidiaz