4

イベントの発生と動作の現在の値に基づいて値を変更したい動作があります。以下の例では、ブール値の動作が True であるか False であるかに基づいて更新される 2 つのカウンターがあります。このコードは<<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
4

1 に答える 1

2

例外は正しいです。動作をそれ自体に関して直接定義しています。

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

... mfix ui

このコードは、結果動作の現在の値がui循環的にそれ自体に依存することを意味します。

再帰を明確に定義するには、常に少しの遅延が必要です。これを行う最も便利な方法は、イベントとstepperorで構築された動作の間で相互再帰を使用することaccumBです。この回答も参照してください。

于 2013-07-14T08:10:47.800 に答える