这里有一些值得深思的地方。
当我编写 monadic 代码时,monad 会对完成的操作进行排序。例如,如果我在 IO monad 中编写:
do a <- doSomething
b <- doSomethingElse
return (a + b)
我知道doSomething
之前会被处决doSomethingElse
。
现在,考虑类似 C 语言的等效代码:
return (doSomething() + doSomethingElse());
C 的语义实际上并没有指定这两个函数调用的评估顺序,因此编译器可以随意移动。
我的问题是这样的:我将如何在 Haskell 中编写单子代码,这也使这个评估顺序未定义?理想情况下,当我的编译器的优化器查看代码并开始移动时,我会获得一些好处。
以下是一些可能无法完成工作但具有正确“精神”的技术:
- 以函数式编写代码,即编写
plus doSomething doSomethingElse
并让plus
调度单子调用。缺点:您无法共享单子操作的结果,并且plus
仍然决定何时评估事物。 - 使用惰性 IO,即 ,
unsafeInterleaveIO
将调度推迟到评估惰性的需求。但是惰性与未定义顺序的严格不同:特别是我确实希望我的所有一元动作都能被执行。 - 惰性 IO,结合立即对所有参数进行排序。特别是,
seq
不强加排序约束。
从这个意义上说,我想要一些比一元排序更灵活但不如完全惰性的东西。