大多数Haskell FRP框架(如AFRP,Yampa和Reactive-banana)在连续时变函数和离散函数之间产生差异。通常他们称他们为行为和事件。
Netwire是一个例外,它使用抑制monoid来模拟事件。这种方法的优点和缺点是什么?
特别是,我对FRP在机器人控制中的应用感兴趣。例如,本文http://haskell.cs.yale.edu/?post_type=publication&p=182展示了一种使用事件对FRP中的任务和HSM抽象进行编码的方法。这可以直接翻译成Netwire吗?
答案 0 :(得分:10)
事件作为潜在抑制信号的优势在于它允许您非常简洁地编码大多数甚至复杂的反应式。想象一下开关在按下时显示“是”,否则显示“否”:
"yes" . switchPressed <|> "no"
这个想法是switchPressed
如果发生相应的事件则表现为身份线,否则就是禁止。这就是<|>
进来的地方。如果第一根电线禁止,它会尝试第二根电线。这是一个由两个按钮(左和右)控制的假想机器人手臂:
robotArm = integral_ 0 . direction
direction =
((-1) . leftPressed <|> 0) +
(1 . rightPressed <|> 0)
虽然机器人手臂是假设的,但这个代码不是。这就是你在Netwire中写这个的方式。
答案 1 :(得分:1)
经过一些试验后,我实施了我需要的行为。基本上,您编写了一个自定义抑制器类型,它可以捕获您需要的事件概念。就我而言,它是
data Inhibitor = Done | Timeout | Interrupt deriving Show
完成意味着正常完成,其余构造函数表示某种错误。
之后,您可以编写所需的任何自定义组合器。在我的情况下,我需要一种方法来停止计算并进一步发出错误信号:
timeout deadline w | deadline <= 0 = inhibit Timeout
| otherwise = mkGen $ \dt a -> do
res <- stepWire w dt a
case res of
(Right o, w') -> return (Right o, timeout (deadline - dt) w')
(Left e, _) -> return (Left e, inhibit e)
这是switchBy的一种变体,它允许您更改一次导线。注意,它传递了新线的抑制信号:
switchOn new w0 =
mkGen $ \dt x' ->
let select w' = do
(mx, w) <- stepWire w' dt x'
case mx of
Left ex -> stepWire (new ex) dt x'
Right x -> return (Right x, switchOn new w)
in select w0
这是( - &gt;)的变体,它捕捉到了打断任务链的想法。
infixr 1 ~>
w1 ~> w2 = switchOn ( \e -> case e of
Done -> w2
_ -> inhibit e
) w1