从这里引用:http://www.haskell.org/haskellwiki/Global_variables
如果您有全球环境, 各种功能从中读取(和 例如,你可以初始化 从配置文件)然后你 应该将其作为参数进行线程化 你的功能(在拥有,非常 可能,在你的'主'中设置它 行动)。如果是显式参数 通过惹恼你,然后你可以 用Monad“隐藏”它。
现在我正在写一些需要访问配置参数的东西,我想知道是否有人可以指向我的教程或任何其他资源来描述monad如何用于此目的。对不起,如果这个问题很愚蠢,我只是开始研究monad。现在阅读Mike Vainer的教程。
答案 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为数不多的正当用途之一。
但是,如果您发现自己需要这样的解决方案,那么您真的需要考虑一下您的设计。很可能你没有考虑将你的功能降低到最低点;如果某些以前的纯函数突然需要运行时参数,那么请查看原因并查看是否可以某种方式利用更高阶函数。例如:
无论哪种方式都涉及