Haskell Language
반응 - 바나나
수색…
외부 이벤트를 라이브러리에 삽입
이 예제는 예를 들어 reactive-banana-wx와 같은 구체적인 GUI 툴킷과 관련이 없습니다. 대신에 임의의 IO
작업을 FRP 기계에 주입하는 방법을 보여줍니다.
Control.Event.Handler
모듈은 AddHandler a
및 a -> IO ()
값 쌍을 만드는 addHandler
함수를 제공합니다. 전자는 반응식 바나나 자체에서 Event a
값을 가져 오는 데 사용되는 반면 후자는 해당 이벤트를 트리거하는 데 사용되는 일반 함수입니다.
import Data.Char (toUpper) import Control.Event.Handler import Reactive.Banana main = do (inputHandler, inputFire) <- newAddHandler
이 경우 처리기 a
매개 변수는 String
유형이지만 컴파일러에서 추론 할 수있는 코드는 나중에 작성됩니다.
이제 FRP 기반 시스템을 설명하는 EventNetwork
를 정의합니다. 이것은 compile
함수를 사용하여 수행됩니다 :
main = do (inputHandler, inputFire) <- newAddHandler compile $ do inputEvent <- fromAddHandler inputHandler
fromAddHandler
함수는 AddHandler a
값을 Event a
로 변환합니다. 다음 예제에서 설명합니다.
마지막으로 사용자 입력시 이벤트를 발생시키는 "이벤트 루프"를 시작합니다.
main = do (inputHandler, inputFire) <- newAddHandler compile $ do ... forever $ do input <- getLine inputFire input
이벤트 유형
반응 형 바나나에서 Event
유형은 시간의 일부 이벤트 스트림을 나타냅니다. Event
는 시간적으로 연속적이지 않다는 의미에서 아날로그 임펄스 신호와 유사합니다. 결과적으로 Event
는 Functor
typeclass의 인스턴스입니다. 서로 다른 시간에 발사 할 수 있기 때문에 두 개의 Event
함께 결합 할 수 없습니다. Event
의 [현재] 값으로 무언가를 할 수 있고 IO
동작으로 반응 할 수 있습니다.
Event
s 값의 변환은 fmap
사용하여 수행됩니다.
main = do (inputHandler, inputFire) <- newAddHandler compile $ do inputEvent <- fromAddHandler inputHandler -- turn all characters in the signal to upper case let inputEvent' = fmap (map toUpper) inputEvent
Event
반응하는 것도 같은 방식으로 수행됩니다. 먼저 a -> IO ()
유형의 액션으로 fmap
을 수행 한 다음 함수를 reactimate
합니다.
main = do (inputHandler, inputFire) <- newAddHandler compile $ do inputEvent <- fromAddHandler inputHandler -- turn all characters in the signal to upper case let inputEvent' = fmap (map toUpper) inputEvent let inputEventReaction = fmap putStrLn inputEvent' -- this has type `Event (IO ()) reactimate inputEventReaction
이제 inputFire "something"
이 호출 될 때마다 "SOMETHING"
이 인쇄됩니다.
행동 유형
지속적인 신호를 표현하기 위해 반응성 바나나 기능 Behavior a
유형. Event
와 달리 Behavior
은 Applicative
이며 n Behavior
순수 함수 ( <$>
및 <*>
)를 사용하여 n Behavior
를 결합 할 수 있습니다.
Event a
에서 Behavior a
를 얻으려면 다음과 같이 accumE
함수가 있습니다.
main = do (inputHandler, inputFire) <- newAddHandler compile $ do ... inputBehavior <- accumE "" $ fmap (\oldValue newValue -> newValue) inputEvent
accumE
는 Behavior
의 초기 값과 Event
에 새로운 값을 설정하는 함수를 포함합니다.
Event
와 마찬가지로 fmap
을 사용하여 현재 Behavior
값으로 작업 할 수 있지만 (<*>)
와 결합 할 수도 있습니다.
main = do (inputHandler, inputFire) <- newAddHandler compile $ do ... inputBehavior <- accumE "" $ fmap (\oldValue newValue -> newValue) inputEvent inputBehavior' <- accumE "" $ fmap (\oldValue newValue -> newValue) inputEvent let constantTrueBehavior = (==) <$> inputBehavior <*> inputBehavior'
Behavior
변화에 반응하기 위해 changes
기능이 있습니다 :
main = do (inputHandler, inputFire) <- newAddHandler compile $ do ... inputBehavior <- accumE "" $ fmap (\oldValue newValue -> newValue) inputEvent inputBehavior' <- accumE "" $ fmap (\oldValue newValue -> newValue) inputEvent let constantTrueBehavior = (==) <$> inputBehavior <*> inputBehavior' inputChanged <- changes inputBehavior
주목해야 할 것은 changes
이 Event a
대신 Event (Future a)
를 반환한다는 것입니다. 이 때문에 반응을 reactimate'
대신에 reactimate
을 reactimate
합니다. 이것에 대한 근거는 문서에서 얻을 수 있습니다.
이벤트 네트워크 작동
EventNetwork
이벤트가 효과를 내기 전에 compile
의해 리턴 된 EventNetwork
가 작동되어야합니다.
main = do
(inputHandler, inputFire) <- newAddHandler
eventNetwork <- compile $ do
inputEvent <- fromAddHandler inputHandler
let inputEventReaction = fmap putStrLn inputEvent
reactimate inputEventReaction
inputFire "This will NOT be printed to the console!"
actuate eventNetwork
inputFire "This WILL be printed to the console!"