mat*_*thk 10 haskell reactive-programming reactive-banana
我正在学习反应性香蕉.为了理解库,我决定实现一个虚拟应用程序,只要有人按下按钮就会增加计数器.
我使用的UI库是Gtk,但这与解释无关.
这是我提出的非常简单的实现:
import Graphics.UI.Gtk
import Reactive.Banana
import Reactive.Banana.Frameworks
makeNetworkDescription addEvent = do
eClick <- fromAddHandler addEvent
reactimate $ (putStrLn . show) <$> (accumE 0 ((+1) <$ eClick))
main :: IO ()
main = do
(addHandler, fireEvent) <- newAddHandler
initGUI
network <- compile $ makeNetworkDescription addHandler
actuate network
window <- windowNew
button <- buttonNew
set window [ containerBorderWidth := 10, containerChild := button ]
set button [ buttonLabel := "Add One" ]
onClicked button $ fireEvent ()
onDestroy window mainQuit
widgetShowAll window
mainGUI
Run Code Online (Sandbox Code Playgroud)
这只是将结果转储到shell中.我在阅读Heinrich Apfelmus 的文章时提出了这个解决方案.请注意,在我的示例中,我没有使用过单个Behavior.
在文章中有一个网络的例子:
makeNetworkDescription addKeyEvent = do
eKey <- fromAddHandler addKeyEvent
let
eOctaveChange = filterMapJust getOctaveChange eKey
bOctave = accumB 3 (changeOctave <$> eOctaveChange)
ePitch = filterMapJust (`lookup` charPitches) eKey
bPitch = stepper PC ePitch
bNote = Note <$> bOctave <*> bPitch
eNoteChanged <- changes bNote
reactimate' $ fmap (\n -> putStrLn ("Now playing " ++ show n))
<$> eNoteChanged
Run Code Online (Sandbox Code Playgroud)
该示例显示了stepper将a 转换Event为a Behavior并带回Event使用changes.在上面的例子中我们可以只使用Event,我猜它没有任何区别(除非我不理解某些东西).
那么有人可以阐明何时使用Behavior以及为什么?我们应该Event尽快转换所有的吗?
在我的小实验中,我看不到Behavior可以使用的地方.
谢谢
Behaviors一直有一个值,而Events只在瞬间有一个值.
可以像在电子表格中一样考虑它 - 大多数数据都是作为稳定值(行为)存在的,它们会在必要时随处可见.(在FRP中,依赖关系可以在没有循环引用问题的情况下进行 - 数据更新从更改的值更新为未更改的值.)您还可以添加按下按钮或执行其他操作时触发的代码,但大多数情况下数据一直可用.
当然,你可以只用事件来做所有这些 - 当这个改变时,读取这个值和那个值并输出这个值,但是以声明的方式表达这些关系并让电子表格或编译器担心什么时候为你更新东西更加清晰.
stepper用于改变在单元格中发生的值的事物,change用于观察单元格和触发动作.输出是命令行上的文本的示例不会因缺少持久数据而受到特别影响,因为无论如何输出都是突发的.
但是,如果您拥有图形用户界面,那么与FRP模型相比,仅限事件模型虽然可能,但确实很常见,但有点麻烦.在FRP中,您只需指定事物之间的关系,而无需明确更新.
没有必要使用行为,类似地,您可以完全在VBA中编写Excel电子表格而不使用公式.数据持久性和等式规范更好.一旦习惯了新的范例,你就不想再回到手动追逐依赖关系和更新内容了.
任何时候FRP网络在Reactive Banana中"做某事"都是因为它对某些输入事件做出了反应.它在系统外部进行任何可观察的事情的唯一方法是连接外部系统以对其生成的事件做出反应(使用reactimate).
因此,如果您所做的只是通过生成输出事件立即对输入事件做出反应,那么不会,您将找不到太多理由使用它Behaviour.
Behaviour对于生成依赖于多个事件流的程序行为非常有用,您必须记住事件在不同时间发生.
一个Event有出现; 具有价值的特定时间点.A Behaviour在所有时间点都有一个值,没有特殊的时间瞬间(除了changes,这很方便,但是有一些模型破坏).
许多GUI中熟悉的一个简单示例是,如果我想对鼠标点击作出反应,并且在不保持shift键的情况下按住Shift键单击与点击不同的操作.通过Behaviour保持指示换档键是否被按下的值,这是微不足道的.如果我只是Event换档按键/释放键,而鼠标点击则更难.
除了更难,它还是更低级别.为什么我必须做复杂的摆弄只是为了实现像shift-click这样的简单概念?在选择之间Behaviour,并Event可以以更接近映射到你想想他们的编程世界之外的方式实施方面你的程序的概念,一个有用的抽象.
这里的一个例子是游戏世界中的可移动物体.我也有一个Event Position它的动作代表所有的时间.或者我可以随时Behaviour Position代表它的位置.通常我会想起的对象为具有在任何时候的位置,所以Behaviour是一个更好的概念契合.
另一个地方Behaviour很有用,用于表示程序可以进行的外部观察,只能检查"当前"值(因为外部系统在发生更改时不会通知您).
例如,假设您的程序必须密切关注温度传感器,并避免在温度过高时启动作业.随着Event Temperature我必须决定了前面多久轮询温度传感器(或以回应什么).然后在我的其他示例中遇到所有相同的问题,即必须手动执行某些操作才能使最后一个温度读数可用于决定是否启动作业的事件.或者我可以fromPoll用来做一个Behaviour Temperature.现在我有一个表示温度随时间变化的值的值,而且我完全从轮询传感器中抽象出来; Reactive Banana本身负责按照可能需要的频率轮询传感器,而我根本不需要任何逻辑!
| 归档时间: |
|
| 查看次数: |
718 次 |
| 最近记录: |