我的应用程序需要一个非常简单的配置,由应用程序启动时初始化的basePath
组成,这样:
data Conf = Conf {
basePath :: FilePath
genericValue :: Int
}
startApp :: IO ()
startApp = do
hd <- getHomeDirectory
let conf = conf (basePath = hd ++ "/some_dir/", genericValue = 10)
-- start to pass around conf
要获取我刚才使用的值:basePath conf
和genericValue conf
。
有没有更好的方法来管理这个并且可能避免在函数中传递这个conf
值?在我身边,我可以找到像Read Monad这样的建议,但我看不到真正的优势。
答案 0 :(得分:1)
就像@Carsten所说,Reader monad的优点是你可以避免必须通过conf
!而不是写:
data Conf = Conf {
basePath :: FilePath
genericValue :: Int
}
somethingSimple :: Conf -> Foo
somethingSimple conf = ...
somethingElse :: Conf -> Bar
somethingElse conf = ...
somethingComplex :: Conf -> (Foo, Bar)
somethingComplex conf = (somethingSimple conf, somethingElse conf)
你写道:
somethingSimple :: Reader Conf Foo
somethingSimple = do
conf <- ask
return ...
somethingElse :: Reader Conf Bar
somethingElse conf = do
conf <- ask
return ...
somethingComplex :: Reader Conf (Foo, Bar)
somethingComplex = do
a <- somethingSimple
b <- somethingElse
return (a, b)
从而完全消除conf
somethingComplex
定义中的Conf
:您只需通过组合其他内容来定义一个读取某些 Conf
值的操作读取某些 Conf
值的操作。您只能传递一次实际的runReader
,即somethingComplex' :: Reader Conf (Foo, Bar)
somethingComplex' = liftM2 (,) somethingSimple somethingElse
!
另外,你可以写下很酷的东西:
var query =
from c in Customers
where !(from n in npConsultant
where n.ConsultantName='X'
select n.Code)
.Contains(c.Code)
&& c.Code < 'AA.0000'
select c.Code, c.Name;