9

大多数 Haskell FRP 框架(如 AFRP、Yampa 和 Reactive-banana)在连续时变函数和离散函数之间有所区别。通常他们称它们为行为和事件。

一个例外是 Netwire,它使用抑制幺半群来模拟事件。这种方法的优缺点是什么?

特别是,我对 FRP 在机器人控制中的应用很感兴趣。例如,这篇论文http://haskell.cs.yale.edu/?post_type=publication&p=182展示了一种使用事件在 FRP 中对任务和 HSM 抽象进行编码的方法。这可以直接翻译成Netwire吗?

4

2 回答 2

10

事件作为潜在抑制信号的优点是它允许您非常简洁地编码最复杂的反应公式。想象一个开关,按下时显示“是”,否则显示“否”:

"yes" . switchPressed <|> "no"

这个想法是,switchPressed如果相应的事件发生,则其作用类似于身份线,否则就禁止。这就是<|>进来的地方。如果第一根电线被抑制,它会尝试第二根。这是一个由两个按钮(左和右)控制的假设机器人手臂:

robotArm = integral_ 0 . direction
direction =
    ((-1) . leftPressed  <|> 0) +
    (1    . rightPressed <|> 0)

虽然机器人手臂是假设的,但此代码不是。这确实是您在 Netwire 中编写此内容的方式。

于 2013-02-01T22:10:12.130 回答
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

这是 (-->) 的变体,它抓住了中断任务链的想法。

infixr 1 ~>

w1 ~> w2 = switchOn ( \e -> case e of
                         Done -> w2
                         _ -> inhibit e
                    ) w1
于 2013-02-06T05:37:43.740 回答