我正在使用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