サーチ…


外部イベントをライブラリに注入する

この例は、例えばreactive-banana-wxのような具体的なGUIツールキットには関係していません。代わりに、任意のIOアクションをFRP機械に注入する方法を示します。

Control.Event.HandlerモジュールはaddHandler関数を提供し、 addHandler AddHandler aa -> IO ()値のペアを作成します。前者は、 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に変換AddHandler aます。これについては、次の例を参照してください。

最後に、ユーザー入力に関するイベントを発生させる「イベントループ」を起動します。

main = do
    (inputHandler, inputFire) <- newAddHandler
    compile $ do
        ...
    forever $ do
        input <- getLine
        inputFire input

イベントタイプ

反応型バナナでは、 Eventタイプは時間内のいくつかのイベントのストリームを表します。 Eventは時間的に連続していないという意味でのアナログインパルス信号に似ています。その結果、 EventFunctor型付きのインスタンスです。 2つの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せるために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とは異なり、 BehaviorApplicativeであり、n個の純粋な関数( <$><*>を使用)を使用してn個のBehaviorを組み合わせることができます。

Event a Behavior aからBehavior aを取得するには、 accumE関数がaccumEます。

main = do
    (inputHandler, inputFire) <- newAddHandler
    compile $ do
        ...
        inputBehavior <- accumE "" $ fmap (\oldValue newValue -> newValue) inputEvent

accumEは、 Behaviorの初期値とEventとり、新しい値に設定する関数を含みます。

Event sと同様に、 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機能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

注目すべき唯一のことは、 changesEvent a代わりにEvent a Event (Future a)返すEvent aです。このため、 reactimate'代わりにreactimate reactimate'を使用する必要がありreactimate 。この背後にある根拠は、ドキュメントから入手できます。

イベントネットワークの起動

EventNetworkイベントが有効になる前に、 compileによって返されたEventNetwork起動compile必要があります。

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!"


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow