7

首先声明一下,由于我对 Haskell 的了解不够深入,我可能完全误解了threepenny-gui 的工作方式,所以请对我的断言持保留态度。:-)

在我看来,一些组合器并不纯粹,例如

stepper :: MonadIO m => a -> Event a -> m (Behavior a)

步进器是否必须在某种类型的 IO monad 上运行(因此它不是纯的),或者我在这里误解了一些东西?第二个问题,如果这些组合子确实不纯,那是为什么?对我来说,这使得构建事件图的代码不如响应式香蕉那么好,因为必须使用 IO monad 而不是纯粹的普通函数。代码似乎变得比反应香蕉更复杂。

更可怕的是,valueChange 从类型上看似乎是纯的

valueChange :: Element -> Event String

但它实际上是在内部使用 unsafeMapIO ,所以它实际上是在做隐藏的 IO 吗?再说一次,我可能会误解一些东西,但这不是 Haskell 中最高的罪过吗?这也令人困惑,我无法从类型中看出回调注册是如何发生的……这在我之前在 Haskell 中从未发生过……这样做是为了让用户不必处理 Frameworks monad 吗?

4

2 回答 2

5

我不是三便士 gui 用户,但我可以通过阅读代码为您提供一些关于您的问题的信息。

首先关于stepper:似乎内部 threpenny-gui 使用 IORefs 来跟踪累积参数。这就是为什么stepper需要MonadIO. 但是,我认为这不需要IO构建您的事件图它只是意味着它必须. 作为 API 用户,这不会给您带来任何尴尬。如果您认为确实如此,请发布更具体的问题。IO

其次,关于valueChange以不安全的功能实现:是的,这在 Haskell 库中很常见。当 Haskell 库的作者知道它们的使用方式对于所有可能的执行路径实际上是安全的时,他们经常使用不安全函数,但不可能向类型系统证明这一点。换句话说,库作者以安全的方式使用不安全的操作,因此您不必这样做!

于 2014-04-13T15:59:03.447 回答
2

这个答案是对Tom Ellis 的补充。它涵盖了我如何从 Threepenny 用户的角度证明一元 FRP 组合器的合理性。

使用 Threepenny,很可能你的事件图的很大一部分将由Elements 构建,因为它们与浏览器中的 DOM 绑定在一起,所以它们存在于UI(一个瘦包装器)中。IO既然如此,删除外部插入诸如反应香蕉之类的东西所涉及的间接性是有意义的(就像旧的反应香蕉三便士包过去所做的那样)。在 reactive-banana-threepenny 的情况下,间接性不仅限于必须使用Frameworksmonad,还涉及在 reactive-banana 和 Threepenny 的不同事件类型之间进行转换(值得考虑的是 Threepenny 中的 FRP 是可选的;您还可以以传统的命令式方式使用事件)。

总的来说,这是一个折衷:为了消除一些间接性并使 API 更容易访问,牺牲了定义事件图的一些简洁性。然而,根据我的经验,这种权衡是值得的。

最后,我在从反应性香蕉三便士转换时与海因里希的讨论可能会对此事有更多的了解。

于 2014-04-13T18:27:00.293 回答