haskell – 如何实现递归依赖自己的反应性香蕉行为?

我有一个行为,我想根据事件的发生和行为的当前值来改变它的值.在下面的示例中,我有两个计数器,它们根据布尔行为是True还是False进行更新.因为这个代码与<< loop>>崩溃了例外,但我不确定如何重组它工作或如何解决这个问题.

{-# 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

最佳答案 例外是正确的,您直接根据自身定义行为.

alternater .. active = (.. <$> active <*> .. , ..)
ui b = do
    let (behavior, ..) = alternater .. (.. <$> b)
    return $.. <*> behavior

... mfix ui

此代码表示ui中结果行为的当前值将以循环方式依赖于自身.

递归总是需要一点延迟才能明确定义.最方便的方法是在事件和使用stepper或accumB构建的行为之间使用相互递归.另见this answer.

点赞