通过monad访问配置参数?

时间:2011-05-21 10:19:21

标签: haskell monads

从这里引用:http://www.haskell.org/haskellwiki/Global_variables

  

如果您有全球环境,   各种功能从中读取(和   例如,你可以初始化   从配置文件)然后你   应该将其作为参数进行线程化   你的功能(在拥有,非常   可能,在你的'主'中设置它   行动)。如果是显式参数   通过惹恼你,然后你可以   用Monad“隐藏”它。

现在我正在写一些需要访问配置参数的东西,我想知道是否有人可以指向我的教程或任何其他资源来描述monad如何用于此目的。对不起,如果这个问题很愚蠢,我只是开始研究monad。现在阅读Mike Vainer的教程。

1 个答案:

答案 0 :(得分:5)

基本思想是你编写这样的代码:

main = do
   parameters <- readConfigurationParametersSomehow
   forever $ do
      myData <- readUserInput
      putStrLn $ bigComplicatedFunction myData parameters

bigComplicatedFunction d params = someFunction params x y z
   where x = function1 params d
         y = function2 params x d
         z = function3 params y

使用IO操作读取“main”函数中的参数,然后将这些参数作为额外参数传递给worker函数。

这种风格的问题在于必须将参数块传递给需要访问它的每个小函数。这是一件令人讨厌的事。您发现调用树中的某些函数有十个级别现在需要一些运行时参数,您必须将该运行时参数作为参数添加到其间的所有函数中。这称为tramp data

monad“解决方案”是将运行时参数嵌入Reader Monad,并使所有函数成为monadic动作。这摆脱了显式的tramp数据参数,但是用monadic类型替换它,并且这个monad实际上正在为你做数据流浪。

命令式世界用全局变量解决了这个问题。在Haskell中,您可以像这样做同样的事情:

parameters = unsafePerformIO readConfigurationParametersSomehow

第一次使用“参数”时,“readConfigurationParametersSomehow”会被执行,从那时起,它就像一个常量值,至少只要你的程序正在运行。这是unsafePerformIO为数不多的正当用途之一。

但是,如果您发现自己需要这样的解决方案,那么您真的需要考虑一下您的设计。很可能你没有考虑将你的功能降低到最低点;如果某些以前的纯函数突然需要运行时参数,那么请查看原因并查看是否可以某种方式利用更高阶函数。例如:

  • 传递使用参数而不是参数本身构建的函数。
  • 让底部的worker函数返回一个函数,结果得到 传递给更高级别的基于参数的函数。
  • 重构您的调用堆栈,以便通过较低级别完成基本操作 底部的基元,它们以与参数相关的方式组成顶部。

无论哪种方式都涉及