首先是一个免责声明,我可能完全误解了三便器的工作方式,因为我对Haskell的知识并不那么先进,所以我的断言就是一丝不苟。 :-)
在我看来,有些组合器并不纯粹。
stepper :: MonadIO m => a -> Event a -> m (Behavior a)
步进器是否必须在某种类型的IO monad上运行(因此它不是纯粹的),或者我在这里误解了什么?第二个问题,如果那些组合器确实不合适,那为什么呢?对我来说,这使得构建事件图的代码比反应性香蕉更好,因为必须使用IO monad而不是纯粹的普通函数。代码似乎变得比在反应性香蕉中变得更复杂。
更可怕的是,valueChange似乎是纯粹的
类型valueChange :: Element -> Event String
但它实际上在内部使用unsafeMapIO,它实际上是在做隐藏的IO吗?再一次,我可能会误解某些东西,但这不是Haskell中最重要的罪吗?这也令人困惑,我无法从类型中判断回叫注册是如何发生的......这在我之前从未在Haskell发生过......这样做是为了让用户不得不处理Frameworks monad吗?
答案 0 :(得分:5)
我不是一个三便携式用户,但我可以通过阅读代码向您提供一些有关您问题的信息。
首先关于stepper
:似乎内部的threpenny-gui使用IORef来跟踪累积的参数。这就是stepper
需要MonadIO
的原因。但是,我认为这不需要IO
构建您的事件图表,只是意味着它必须在IO
中运行。这不应该导致您作为API用户的任何尴尬。如果您认为确实如此,请发布更具体的问题。
其次关于valueChange
在不安全函数方面的实现:是的,这在Haskell库中很常见。 Haskell库作者在知道使用它们的方式对所有可能的执行路径实际上是安全的时,通常会使用不安全的函数,但是不可能向类型系统证明这一点。换句话说,图书馆作者以安全的方式使用不安全的操作,因此您不必使用!
答案 1 :(得分:2)
这个答案是对Tom Ellis'的补充。它涵盖了我如何从Threepenny用户的角度证明monadic FRP组合器的合理性。
使用Threepenny,可能性很大一部分事件图将来自Element
s,它们位于UI
(IO
的薄包装器)中,因为它们是并列的到浏览器中的DOM。既然如此,删除外部插入像reactive-banana这样的东西(就像旧的reactive-banana-threepenny包一样)是有意义的。在反应性香蕉 - 三便士的情况下,间接不仅限于必须使用Frameworks
monad,而且它还涉及在反应香蕉和Threepenny的不同事件类型之间进行转换(也值得考虑FRP)在Threepenny中是可选的;你也可以以传统的,强制性的方式使用事件。
总的来说,这是一个权衡:消除一些间接性并使API更容易被访问,牺牲了定义事件图的一些清洁度。然而,根据我的经验,权衡是值得的。
在结束语中,这个discussion I had with Heinrich在转换为反应性香蕉 - 三便士的时候可能会对这个问题有所了解。