Haskell Language                
            Реактивный-банан
        
        
            
    Поиск…
Внедрение внешних событий в библиотеку
 Этот пример не привязан к какому-либо конкретному набору инструментов GUI, например, реактивный банан-wx. Вместо этого он показывает, как вводить арбитационные операции IO в машины FRP. 
 Модуль Control.Event.Handler предоставляет функцию addHandler которая создает пару значений AddHandler a и a -> IO () . Первый используется самим реактивным бананом, чтобы получить значение Event a , а последнее - это простая функция, которая используется для запуска соответствующего события. 
import Data.Char (toUpper)
import Control.Event.Handler
import Reactive.Banana
main = do
    (inputHandler, inputFire) <- newAddHandler
  В нашем случае параметр обработчика имеет тип a String , , но код , который позволяет компилятору сделать вывод , что будет написано позже. 
 Теперь мы определяем EventNetwork которая описывает нашу систему, основанную на FRP. Это делается с помощью функции 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 класса типов только. Вы не можете объединить два Event вместе, потому что они могут срабатывать в разное время. Вы можете сделать что-то со значением [current] 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 осуществляется таким же образом. Сначала вы fmap его с помощью действия типа a -> IO () а затем передадите его в функцию 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" inputFire "something" называется, "SOMETHING" будет напечатано. 
Тип поведения
 Чтобы представить непрерывные сигналы, реакционно-банановые функции Behavior a типа. В отличие от Event , Behavior является Applicative , которое позволяет комбинировать n Behavior s с помощью n-ary чистой функции (используя <$> и <*> ). 
 Чтобы получить Behavior a от Event a существует функция accumE : 
main = do
    (inputHandler, inputFire) <- newAddHandler
    compile $ do
        ...
        inputBehavior <- accumE "" $ fmap (\oldValue newValue -> newValue) inputEvent
  accumE принимает начальное значение Behavior и Event , содержащее функцию, которая устанавливает ее в новое значение. 
 Как и в случае с Event s, вы можете использовать fmap для работы с текущим значением Behavior s, но вы также можете комбинировать их с (<*>) . 
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 (Future a) вместо Event a . Из-за этого reactimate' следует использовать вместо того, чтобы reactimate . Обоснование этого можно получить из документации. 
Приведение в действие EventNetworks
 EventNetwork s, возвращаемая 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!"