哈斯克尔。向程序提供参数(纯方式)
我对向我的程序提供参数的可能方法感兴趣。这是一个物理模拟,我需要输入温度、步数等。
但是我需要这些参数是纯粹的,所以我不能以任何方式使用 IO。因此,每次至少必须重新编译我的程序的一部分。实现这一目标的最佳方法是什么?
据我记得 xmonad 使用相同的技术。
UPD 看起来 Dyre 满足了我的需要。 http://hackage.haskell.org/package/dyre 应该尝试一下。
UPD2 Dyre 做了一些不同的事情。
I'm interested in possible ways to supply parameters into my program. It is a physical simulation and I need to input temperature, number of steps and so on.
However I need these parameters to be pure so I can't use IO in any way. Hence at least part of my program have to be recompiled each time. What is the best method to achieve this?
As far as I remember xmonad uses the same technique.
UPD It seems Dyre does what I need. http://hackage.haskell.org/package/dyre Shall try it.
UPD2 Dyre does a bit different thing.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
来自对该问题的评论:
这里隐含着一些误解,需要加以审查。
首先,众所周知的一个:如果您不确定效率,请先不要优化!首先以合理的方式编写程序,然后在需要提高速度时对其进行分析。仅当您知道抢占式优化会降低算法的时间或空间复杂度,或者它会显着减少程序计算密集型部分中的常数因子时,它才是一个好主意。这里的情况也不是这样。
其次,函数应该接受所需数量的参数。这听起来像是一个同义反复,事实上也确实如此,但关键是减少传递给实际使用这些参数的函数的参数数量是没有意义的。如果它实际上没有使用某些参数,请删除它们;如果在子表达式中一起使用参数组,请将它们提取为单独的函数并传入结果;如果一堆参数一起传递给多个函数,请将它们捆绑在记录类型中并将其作为单个参数传递;但不要为了消除参数而试图消除它们。这毫无意义!
此外,从问题本身来看:
纯参数则不然。它们是不变的价值观。您可以在源代码中的其他位置定义它们,但编译后它们是固定且不可变的。如果程序需要访问编译后确实更改的参数,则必须使用I/O。这实际上就是 I/O 的定义!
请记住,即使您需要在
IO
计算中获取值,所有实际逻辑都可以在纯函数中完成,如下所示:函数
lotsOfCalculations
,如下所示以及它使用的其他任何东西,都将是纯函数。IO
的唯一用途是获取参数。另外,为了更简洁,请注意上面的代码也可以写为
main = getParameter >>= print 。很多计算
。From a comment on the question:
There are some misconceptions implicit here that need to be examined.
First, the well-known one: If you're not sure about efficiency, don't optimize yet! Write the program in a way that's sensible first, then profile it if needed to improve speed. Preemptive optimization is only a good idea when you know it will reduce the time or space complexity of your algorithm, or if it will significantly reduce constant factors in a very computation-intensive part of the program. Neither is the case here.
Second, functions are supposed to take as many parameters as they need. This sounds like a tautology, and it nearly is, but the point is that it makes no sense to reduce the number of arguments passed to a function that actually uses those arguments. If it doesn't actually use some arguments, remove those; if groups of arguments are used together in subexpressions, extract those as separate functions and pass in the result instead; if a bunch of arguments are passed around together to multiple functions, bundle them in a record type and pass that as a single argument; but don't try to eliminate parameters for the sake of eliminating them. That makes no sense!
Furthermore, from the question itself:
Pure parameters aren't. They're constant values. You may define them elsewhere in the source code, but after compilation they're fixed and immutable. If the program needs access to parameters that do change after compilation, that has to use I/O. That's practically the definition of I/O!
Keep in mind that even if you need to obtain values in an
IO
computation, all the actual logic can be done in a pure function, like this:The function
lotsOfCalculations
, as well as anything else it uses, will be pure functions. The only use ofIO
is to get the parameters.Also, to be more concise, note that the above code could also be written as
main = getParameter >>= print . lotsOfCalculations
.使用阅读器 monad,例如
Reader r
来自 Control.Monad.Reader。然后使用runReader
运行计算。您将模拟参数传递给
runReader
,然后模拟的组件可以使用ask
和asks
访问它们。(注意:这要求您将所有参数捆绑到一个数据类型中。)
Use a reader monad, for example
Reader r
from Control.Monad.Reader. Then run the computation usingrunReader
.You pass the simulation parameters to
runReader
, then the components of your simulation can access them usingask
andasks
.(Note: this requires that you bundle up all the parameters into a single data type.)
除非您在解释器内运行此程序,否则您将不得不在某些时候涉足 IO。最有可能通过主函数,这是不纯粹的。
无论如何,只需将您的函数设计为纯粹的即可。在不纯函数中,您可以使用 Maybe monad 来净化值,然后将它们传递(或在 Nothing 的情况下不传递)它们到纯函数中。
请记住,要从程序中获取任何类型的输出,它将需要显式(例如主函数)或隐式(解释器)运行IO函数。
Unless you're running this program inside the interpreter, you'll have to dip into IO at some point. Most likely through the main function, which is impure.
In any case, just design your functions as pure. In your impure functions, you can use the
Maybe
monad to purify values, then pass (or not pass in the case of Nothing) them into your pure functions.Keep in mind, to get any sort of output from the program, it will need to run through an IO function, either explicitly (e.g. main function) or implicitly (the interpreter).
尝试使用闭包,
一般来说,在 Haskell 中,当你试图违反纯度时,就会发生不好的事情。例如,将随机数生成器调用包装在
unsafePerformIO
中意味着您不会获得随机数,因为它将开始重用计算(以意想不到的方式)。此外,还有记录类型,因此您可以创建类似的内容
Try using a closure,
In general, in Haskell, when you try to violate purity, bad things happen. For example, wrapping a random number generator call in
unsafePerformIO
means you don't get random numbers, since it will start reusing the calculation (in unexpected ways).Also, there's record types, so you can create something like