事件应该是外部可变的吗?

时间:2012-01-17 23:52:22

标签: scala haskell programming-languages functional-programming frp

我正在玩FRP,并且想知道应该如何公开处理事件'发生'的行为。通过这个,我的意思是程序员应该能够在FRP上下文中执行以下操作:

event.occur(now, 5)

我从未在任何FRP论文中看到过这样的例子,对我来说感觉不对。我觉得FRP框架应该真正隐藏这种类型的动作,并且事件的发生应该只在幕后发生。我是否正确地想到这一点?

为了澄清,我的方法是让“发生”只能由Event类本身访问。如果需要某些外部源的抽象(例如鼠标),可以通过扩展Event类来构建。这样就可以抽象出所有处理事件创建的逻辑。

1 个答案:

答案 0 :(得分:6)

好吧,如果FRP库公开了一种绑定到外部事件的方法 - 例如现有的基于事件的框架 - 然后必须提供与此相当的功能,否则它无法与外部世界交互。

但问题是:“外部”是什么意思? FRP系统本身通常被认为是纯粹的,因此从FRP系统内部执行像event.occur(now, 5)这样的副作用代码的想法甚至没有意义。当然,通常会提供执行此类代码以响应FRP事件 的工具,但这通常不是纯编程模型的一部分,而是作为将网络作为接口连接的工具。整个外部世界。

因此,在我看来,有两种方法可以解释这个问题:

  1. 是否可以从FRP系统外部触发事件? - 肯定是的,因为这是与外部世界接口所必需的,但这不会影响FRP本身的编程模型
  2. 是否有可能从FRP系统的“内部”触发事件,假设某些设施执行副作用代码以响应事件? - 同样是,因为允许正常的一面 - 有效的代码导致事件但是在响应事件时执行的代码中禁止它似乎是一种非常奇怪(并且可以绕过)的限制,因为该设施的意图是与外界联系。
  3. 实际上,即使您明确禁止它,也可能会产生类似#2的内容:考虑进行设置,以便在事件switchToWindow 3触发时执行buttonClicked,例如(使用reactive-banana表示法):

    reactimate (switchToWindow 3 <$ buttonClicked)
    

    并说我们有一个活动

    newWindowFocused :: Event Int
    

    我们设置的反应导致newWindowFocused事件触发,即使由于事件而执行的内部代码中的事件被阻止也会被触发。

    现在,我到目前为止所说的一切只涉及“外部”事件:那些没有用纯粹的FRP表达的事件,而是明确地创建来代表FRP系统之外的外部世界发生的事件。如果您在询问是否应该有一个工具在纯定义的事件中引起特殊情况,那么我的回答是:绝对不是!这会破坏系统的含义,因为当fmap f (union e1 e2)f x出现值e1时,突然e2并不意味着“值x出现” ,但是当f xe1出现值e2时,或者当某些外部代码随机决定触发它时,“以值x出现”。

    这样的设施不仅对FRP系统的行为进行推理基本上没有意义, 1 它也违反了引用透明度:如果你构造了两个相当于fmap f (union e1 e2)的事件,然后你可以通过触发一个并注意到另一个没有发生来区分它们。在所有情况下,您都无法阻止这种情况:想象fmap g (union e1 e2),其中f计算与g相同的函数;功能上的平等是不可判定的:)

    当然,完全可以用不纯的语言实现FRP,但我认为提供一种违反FRP系统本身参考透明度的方法是一件非常糟糕的事情,因为它毕竟是一个纯粹的模型。

    如果我理解正确的话,你在API中解决这个缺陷的方法(即公开occur,打破等价事件的引用透明度等等,就像我上面所说的那样)将是{{ 1}} occur类的内部,因此无法从外部使用它。我同意,如果您在内部需要Event,这是正确的解决方案。我也同意,如果您通过子类化occur完成外部事件的实现,则将它公开给子类是合理的。这属于“外界胶水”,它超出了FRP模型本身的范围,因此完全可以让它以这种方式“破坏规则” - 毕竟,这基本上就是它的因副作用而扰乱系统:)

    所以,最后:

    不,事件不应公开此界面。

    是的,你认为这是正确的:)

    1 当然,你可以说外部事件会这样做完全停止,因为系统的整个行为最终取决于连接到的“边缘”外面的世界,但这不是真的:是的,你不能真正假设外部事件自己,但你仍然可以依靠你建立的所有东西来遵守他们的建筑。为每个事件提供“外部射击”设施意味着没有任何建筑任何法律。