Comparing revisions for page Reflex

Back to history list
  == Headline ==

Reflex is a [[Functional Reactive Programming]] library in [[Language:Haskell|Haskell]]

== Reflex ==

[http://hackage.haskell.org/package/reflex]: Reflex is a haskell library for functional reactive programming in haskell.


Reflex provides the abstractions described in [[Functional Reactive Programming]] (behaviors and events), functions to work with them, and an additional abstraction called Dynamics. For our intents and purposes, we’ll consider dynamics to be the same as behaviors, since discussing the details of it would be out of the scope of this tutorial(2).


(2) In a very short note: Reflex is implemented with push-pull evaluation, and thus often requires explicit push notifications to update things like the DOM. Event push notifications when they occur, but Behaviors don’t push anything. A Dynamic is a combination of an Event and Behavior, meaning it’s a continuous time-varying value that pushes notification whenever it changes, and fills the spaces where we need a behaviour and to know when the value changes.

=== Building UIs with Reflex-Dom ===

To build a UI we’ll use reflex-dom which is a haskell library that provides a monadic interface for building a DOM-based UI with functional reactive programming abstractions from reflex.

A DOM user interface is defined with element tags. A webpage can have many elements such as divisions and text paragraphs.


This is a paragraph.

This is the second division.

Would define a webpage with two divisions (
). The first division has a paragraph (

) and a button (

This is the second division.

Would define a webpage with two divisions (
). The first division has a paragraph (

) and a button (

After button

An input text box has a continuous time-varying value: What the user has input in the box. We can model the value inside the input box with a behavior! As with the button, we already have a function that returns a Widget computation that creates an input box and which returns a behavior of the value in the text box. input :: Widget (Dynamic Text) ex5 = el "div" $ do inputBehavior <- input return () would correspond to
Lastly, we have a function for displaying a behavior of a string. Whatever the value of the string is at the current time, is what’s displayed on the string. Non-surprisingly, this function is called dynText. dynText :: Dynamic Text -> Widget () ex6 = el "div" $ do inputBehavior <- input el "p" (dynText inputBehavior) what would this look like?

???

not so simple, would require javascript Next we’ll look at some UI-independent combinators on events and behaviors, and an example of how we can use them in building a more complex UI. [3] In fact, Widget x is the monad (Widget :: * -> * -> *), where x is a type parameter to guarantee contexts don’t get mixed. === Reflex Combinators === In this section we describe some reflex combinators for manipulating events and behaviors. Remember that for our purposes we’ll consider dynamics to be the same as behaviors but with a different name. We can create a behavior which is constant over all time, given the constant value. constDyn :: a -> Dynamic a d1 = constDyn 2 -- is 2 at all points in time We can create a behavior that changes to the value of an event every time said event occurs, provided an initial value for the behavior to have before the first occurrence of the event is given. holdDyn :: a -> Event a -> Widget (Dynamic a) d2 = holdDyn 'A' keyPress -- until the first event occurrence is 'A', and then it's the value of the event occurrence where keyPress :: Event Char We can create a behavior that changes everytime an event occurs, provided the function to fold the event value with the current value, and an initial value. This is somewhat similar to a list fold, but it’s a actually a fold across time. foldDyn :: (a -> b -> b) -> b -> Event a -> m (Dynamic b) -- Note: foldr :: (a -> b -> b) -> b -> [a] -> b As an example, we can now define an application that displays a button and the number of times said button has been clicked (remember how behaviors instance Functor) app = el "div" $ do clickEvt <- button "Click me!" clickAmount <- foldDyn (\_ acc -> acc+1) 0 clickEvt el "p" (dynText (displayAmt <$> clickAmount)) where displayAmt x = "Clicked " <> showT x <> " times." -- Note how length for normal functions can be defined as length ls = foldr (\_ acc -> acc+1) 0 ls This might be a bit confusing so we’ll walk through each value. clickEvt has type Event (), representing the occurrences of a button click through time clickAmount has type Dynamic Int. We start with the value 0, and when the Event () occurs, we apply the lambda of type () -> Int -> Int which ignores the first argument and adds +1 to the existing counter. displayAmt <$> clickAmount has type Dynamic Text, meaning we can display it with dynText. Note that displayAmt :: Int -> Text, and we fmap it over Dynamic Int (hence why we get Dynamic Text). If you wrote something similar to this code, you’d see an application with a button and a text paragraph with a counter. Every time you click the button the counter will increase. Lastly, we’ll cover a function that allows us to sample the value of a behavior every time an event occurs. tagPromptlyDyn :: Dynamic a -> Event b -> Event a -- e1 will occur with the value of the input box every time the button is clicked e1 :: Event Text e1 = do click <- button "Sample input box value" valBehv <- input return (tagPromptlyDyn valBehv click) In [[Contribution:haskellReflex]] you can see a full application for an illustration of using Reflex. == Metadata == * [[instanceOf::FRP library]] * [[instanceOf::Haskell technology]] * [[sameAs::http://hackage.haskell.org/package/reflex]] * * [[facilitates::Functional Reactive Programming]]