2013-07-13 4 views
4

나는 행동 값과 행동의 현재 값에 따라 값을 바꾸고 싶은 행동이있다. 아래 예제에서는 부울 동작이 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 
+0

'accumb '를 사용하여'result'를 계산하므로'behavior' (내부'ui')는 아마도 괜찮을 것이라고 생각합니다. 문제가 'evt'라고 생각합니다. 'evt'도'b'에 의존하지만, 그것을 계산하는 데 사용되는 지연되거나 관찰 가능한 원시 요소가 없습니다. 불행히도, 나는 그 순간에 당신이 그것을 고치기 위해 무엇을해야만하는지 가장 안 좋은 생각이 없습니다. –

+0

사실,'evi (return $ stepper id (fmap (*** id) never) <*> 동작'으로 바꾸면 evt에 대한 참조를 제거 할 때 문제가되는'ui' 내부의' 나는 여전히 <>을 만나고 있습니다. – merijn

+0

흠 ...이 경우 버그 일 수 있습니까? 문서에서는 'accumB'가 관찰 가능하다고 가정합니다. '스테퍼 '와 동일합니다. –

답변

2

예외는 정확합니다. 동작 자체를 직접 정의하고 있습니다.

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

... mfix ui 

이 코드 ui의 결과 거동의 현재 값은 원형 방식 자체에 달려 있다는 것을 의미한다.

재귀는 항상 잘 정의되기 위해 약간의 지연이 필요합니다. 이를 수행하는 가장 편리한 방법은 이벤트와 stepper 또는 accumB으로 빌드 된 동작 간의 상호 재귀를 사용하는 것입니다. this answer도 참조하십시오.

+0

맞아, 원래의 예제를 단순화하려고 시도했지만 Bool의 동작에 어디에도 초기 사양이 없음을 알지 못했습니다. 그러나 만약 내가 정의를 ui에서''let delay = stepper True $ (fst <$> b) <@ eInput''과''let (behavior, evt) = alternater eInput delay''를 바꾸면 나는 여전히 루프를 얻습니다. , 모든 초기 값을 지정하는 것처럼 보이지만 (accumB를 사용하는 카운터와 지연이 스테퍼 임), 뭔가 빠졌습니까? – merijn