功能反应式编程优于事件监听器

tld*_*ldr 7 javascript functional-programming event-handling frp bacon.js

我一直听到很多关于功能反应式编程的知识,并决定查看重要的是什么.通过bacon.js文档,似乎主要区别在于,不是在组件上设置事件侦听器,而是在其上创建事件流,并将事件处理程序传递到流中.换句话说,我真正做的就是将事件处理程序从组件移动到事件流.是吗?如果是这样,这样做的最大好处是什么?

Hei*_*mus 13

功能反应式编程(FRP)的关键点是语法属性:

值的动态行为在声明时指定.

例如,考虑一个可以通过按下按钮来计数或减少计数器的计数器.在命令式的风格中,您可能会这样写:

counter := 0                               -- initial value
on buttonUp   = (counter := counter + 1)   -- change it later
on buttonDown = (counter := counter - 1)
Run Code Online (Sandbox Code Playgroud)

首先,计数器以初始值声明.然后,在代码的后面部分中,您可以更改该值.现在,如果有人问你"在任何给定的时刻,有什么价值counter?",你必须查看引用该名称的代码的所有部分counter,因为这是可以更改的地方.

相反,在使用FRP样式代码时,可以通过查看代码中的一个位置来回答问题:counter声明的位置.例如,在Haskell中,您可以将计数器编写为

counter :: Behavior Int
counter = accumulate ($) 0
            (fmap (+1) buttonUp
             `union` fmap (subtract 1) buttonDown)
Run Code Online (Sandbox Code Playgroud)

右侧包含了解counter在任何给定时刻的价值所需的所有信息.特别是,你看,它可以是一个变化buttonUpbuttonDown,仅此而已.您不必筛选代码,查找计数器可能更改的位置,不,只需查看其声明并从那里进行跟进就足够了.

这就是为什么FRP代码比基于事件的意大利面条代码更容易出错的原因.

另请参阅我的threepenny-gui库的一些初步文档.

  • @ rodrigo-silveira我的意思是,为了知道`counter.getValue()`返回什么,你必须在代码中找到所有出现的`counter.setValue(...)`.相反,对于FRP,这些事件都可以从"counter"的声明中获得. (2认同)

Ber*_*rgi 7

是吗?

不,这是关于事件流.你仍然会在最后将侦听器附加到它们以执行效果,但是在源和目标之间你有一个非常强大的抽象.

这样做的最大好处是什么?

该事件流确实有很多高阶函数能够轻松地与他们打交道,并撰写他们无需编写了所有的容易出错的样板代码.

正如文档所说的那样,培根

将您的活动面条到清洁声明风水腊肉,通过切换从迫切需要的功能.这就像更换嵌套for与像函数式编程的概念-loops mapfilter.停止处理单个事件并改为使用事件流.与结合您的数据mergecombine[并运用]重型武器[象] flatMapcombineTemplate.

  • 它不仅是转换(如简单的`filter` /`map` /`reduce`操作),还有*composability*,这是函数式编程的关键. (2认同)