IO 运行 应该在传播期间内联吗?

Should IO run inline during propagation?

我正在尝试在 Idris 中编写 FRP 库。此库设计为 运行 在单线程环境中。未来实施 MonadAlign。我想用这些简化的类型签名实现功能:

createFutureResolveLater : (Future a, a -> IO ()) -- later time

createFutureResolveNow : a -> IO (Future a) -- current time

pure : a -> Future a -- before everything

align : Future a -> Future a -> Future (These a b) -- min of two times

join : Future (Future a)) -> Future a -- max of two times

exeEvent : Future (IO a) -> IO (Future a) -- ??

simultaneous : Future a -> Future b -> Future Bool -- min of two times

subFuture : Future a -> (a -> IO ()) -> IO ()

在我看来很明显

simultaneous a a, simultaneous a (fmap f a), etc.

应该是解析为 true 的未来。

do
    oe <- exeEvent ie
    let s = simultaneous oe ie
    ...

应该解析为真吗?

在 reactive-banana 中,s 为假。请参阅 http://hackage.haskell.org/package/reactive-banana-1.2.1.0/docs/Reactive-Banana-Frameworks.html

中的 mapEventIO

在反射中,s 也很可能是假的。请参阅 https://daig.github.io/reflex/Reflex-PerformEvent-Class.html

中的 performEvent

为什么这些库作者选择 s 为假?

正在尝试弄清楚你在问什么。我想您想知道如何解释 IO 需要时间的操作,不是吗?因为如果 IO 动作是瞬时的,这就不是问题了。尽管对我来说还有一个问题,即 IO 操作会阻塞直到未来发生还是异步安排它?

如果这是一个 non-blocking 调用,我会说它应该等到 IO 操作完成。 (我也会称它为 schedFuture 或类似的名称,以表明它不会阻塞。)否则你可能会遇到 Future 的情况,但它的价值仍然存在不可用,这可能会搞砸合并事件等功能的逻辑

如果这是一个阻塞调用,我会改为提供

waitFuture :: Future a -> IO a

并让用户处理其余部分(例如,如果他们想保留时间,他们可以 fmap (const x) 在原来的未来,他们可以在操作完成时使用 now :: IO (Future ()) 如果他们想要它, ETC。)。如果你能为他们想出好的名字,那么为他们提供组合器可能是值得的,否则他们很容易,我只是平底船。

我还发现在制作这样的系统时区分 "morally instantaneous" IO 操作和可能阻塞的操作很有帮助。我想这与 javascript 对异步和常规堆栈调用的区别是平行的。像这样模糊的问题很多,对应的显而易见的答案往往取决于这个区分。