如何实现递归依赖于自己的反应性香蕉行为? [英] How to implement reactive-banana behaviors that recursively depend on themself?
问题描述
我有一个行为,我想根据事件的发生和行为的当前值来改变它的值。在下面的例子中,我有两个计数器根据布尔行为是True还是False来更新。因为这段代码崩溃时发生了一个<< loop>>
异常,但我不确定如何重构它以工作或解决该问题。
I have a Behavior whose value I want to change based on the occurrence of an Event and the Behavior's current value. In the example below I have two counters that are updated based on whether a boolean behaviour is True or False. As it is this code crashes with a <<loop>>
exception, but I'm unsure how to restructure it to work or how else to approach this problem.
{-# LANGUAGE ScopedTypeVariables #-}
import Reactive.Banana
import Reactive.Banana.Frameworks
import Control.Arrow
import Control.Concurrent
import Control.Monad
import Control.Monad.Fix
counter :: Bool -> Event t Int -> Behavior t Bool -> (Behavior t Int, Event t (Bool -> Bool))
counter b input active = (result, whenE ((b/=) <$> active) (fmap (const not) input))
where result = accumB 0 (fmap (+) evt')
evt' = whenE ((b==) <$> active) input
alternater :: Event t Int -> Behavior t Bool -> (Behavior t (Bool, (Int, Int)), Event t (Bool -> Bool))
alternater input active = ((,) <$> active <*> ((,) <$> fst t1 <*> fst t2), snd t1 `union` snd t2)
where t1 = counter True input active
t2 = counter False input active
main :: IO ()
main = do
(inputHandler, fireInput) <- newAddHandler
let network :: forall t . Frameworks t => Moment t ()
network = do
eInput <- fromAddHandler inputHandler
let ui :: Behavior t (Bool, (Int, Int)) -> Moment t (Behavior t (Bool, (Int, Int)))
ui b = do
let (behavior, evt) = alternater eInput (fst <$> b)
return $ stepper id (fmap (***id) evt) <*> behavior
output <- changes =<< mfix ui
reactimate $ putStrLn . show <$> output
forkIO $ actuate =<< compile network
forever $ getLine >>= fireInput . read
推荐答案
异常是正确的,您正在定义行为直接就其本身而言。
The exception is correct, you are defining a behavior directly in terms of itself.
alternater .. active = (.. <$> active <*> .. , ..)
ui b = do
let (behavior, ..) = alternater .. (.. <$> b)
return $ .. <*> behavior
... mfix ui
此代码表示当前值在 ui
中的结果行为将以循环方式依赖于自身。
This code means that the current value of the result behavior in ui
would depend on itself in a circular way.
递归总是需要一点点延迟定义明确。最简便的方法是在事件和使用 stepper
或 accumB
构建的行为之间使用相互递归。另请参阅此答案。
Recursion always needs a little delay to be well-defined. The most convenient way to do that is to use mutual recursion between an event and a behavior built with stepper
or accumB
. See also this answer.
这篇关于如何实现递归依赖于自己的反应性香蕉行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!