Comparing Elm with Reflex
Tags: functional, programming, haskell, elm
Published: 2021-03-22 14:38:30

Author: Volodya Kalnitsky

# Introduction

This post deals with two essentially different approaches to reactive programming.

Elm, unlike Reflex, is a separate language, not a library, which is why it’s not quite correct to compare them. Nevertheless, it is possible to show the difference between the approaches and describe the _practical_ challenges you may face when developing software using each of the technologies.

![](https://blog.typeable.io/images/reflex-vs-elm/1.png)

# Elm and TEA

[Elm](https://elm-lang.org/) is a functional programming language used to create reactive web applications. Elm applications must follow [The Elm Architecture (TEA)](https://guide.elm-lang.org/architecture/), i.e. a simple design pattern implying the code division into three parts – model, view and update:

* Model includes the data used in the application, as well as the data describing the messages needed for any interaction.
* View is the function transforming the model into the user interface.
* Update is the function responsible for the status update (it receives the model and message and returns the updated model).


# FRP in a Reflex style

[Reflex](https://reflex-frp.org/) is the framework that allows creating reactive web applications in Haskell.

In contrast to Elm, Reflex doesn’t impose any strict constraints on the application architecture. The framework provides abstractions to control the state and the programmer is free to use them in any combination.

There are three main abstractions, namely Event, Behavior and Dynamic.


## Event

[Event](https://hackage.haskell.org/package/reflex-0.6.1/docs/Reflex-Class.html#t:Event) is an abstraction used to describe discrete events occurring from time to time instantaneously. The events are parametrized by the type of the value they contain.


## Behavior

[Behavior](https://hackage.haskell.org/package/reflex-0.6.1/docs/Reflex-Class.html#t:Behavior) can be regarded as a changing value which can be sampled at any point in time. However, it is not possible to “subscribe” to the value update.


## Dynamic = Event + Behavior

Conceptually, [Dynamic](https://hackage.haskell.org/package/reflex-0.6.1/docs/Reflex-Class.html#t:Dynamic) is the pair consisting of the Event and Behavior.

You can obtain each of the Dynamic components using the pure functions [`updated`](https://hackage.haskell.org/package/reflex-0.8.0.0/docs/Reflex-Class.html#v:updated) and [`current`](https://hackage.haskell.org/package/reflex-0.8.0.0/docs/Reflex-Class.html#v:current):

```haskell
current :: … => Dynamic t a -> Behavior t a
updated :: … => Dynamic t a -> Event t a
```

(Here and elsewhere, the parameter of t type can be ignored – this is an implementation feature. For the sake of legibility, the constraints in type signatures here and in some places below are replaced with ellipses).

Dynamic guarantees that the following invariants hold:

* After the event is launched, the behavior changes its own value to a value from the Event.
* Each change in the behavior is preceded by an event launching.

It’s not possible to create an “incorrect” Dynamic using the library functions.

Dynamic is convenient for the programmer because it rules out the errors relating to any status updates missed. All events potentially affecting the Dynamic must be explicitly listed during its creation, which is why the errors relating to an accidental status update (for example, from another part of the program) are also eliminated.

It’s important to note that the Dynamic can be “updated” with the same value it had before. If the values in the Dynamic determine a DOM section, it will be rebuilt because the framework is not able to test random values for equality (further in the text we will show how this can be avoided).


# Code Examples

We will consider two implementations of an interactive questionnaire widget based on the two technologies. The users see a list of questions with the answer options known in advance. The users select one answer for each question from these options and can compare their answers with the correct ones after clicking on the check button.

The check button must not be available until an answer is selected for each of the questions. After the check, we must show the score, i.e. the number of correct answers.

To find the complete code of both applications [follow the link](https://github.com/typeable/blog-posts-ru/tree/master/elm-vs-reflex). (For convenience, the links to the main files are [Elm](https://github.com/typeable/blog-posts-ru/blob/main/elm-vs-reflex/elm-quiz-demo/src/Main.elm), [Reflex](https://github.com/typeable/blog-posts-ru/blob/main/elm-vs-reflex/reflex-quiz-demo/frontend/src/Frontend.hs)).

For the Reflex example, we use the [Obelisk](https://github.com/obsidiansystems/obelisk) framework. It allows implementing both the frontend and the backend and is also responsible for the server-side rendering and routing. We will use it as the build system only (we have no backend here).

## Description of the Application State

Like Haskell, Elm supports [algebraic data types](https://en.wikipedia.org/wiki/Algebraic_data_type). The code below declares the data types we need to create our application (Model). Similar declarations in Haskell are not conceptually different in any way, so we will not show them.

### Elm

```elm
type alias QuestionText = String

type alias AnswerText = String

type IsChosen = Chosen | NotChosen

type IsCorrect = Correct | Incorrect

type CanCheckAnswers = CanCheckAnswers | CantCheckAnswers

type AreAnswersShown = AnswersShown | AnswersHidden

type alias Answer =
  { answerText : AnswerText
  , isCorrect : IsCorrect
  }

type Score
  = NoScore
  | Score { totalQuestions : Int, correctAnswers : Int }

type alias Questions = List (QuestionText, List (Answer, IsChosen))

type alias Model =
  { areAnswersShown : AreAnswersShown
  , allQuestions : Questions
  , canCheckAnswers : CanCheckAnswers
  , score : Score
  }
```

## Message/Event Description

### Elm

The type describing an Elm message contains all the values we may need to update the status. We will use two indices to select an answer option: the question number and the number of the answer to this question. For the sake of simplicity, we also store the new value IsChosen in the event payload.

```elm
type Msg
  = SelectAnswer
  { questionNumber : Int
  , answerNumber : Int
  , isChosen : IsChosen }
  | CheckAnswers
```


### Reflex

In Reflex, we deal with several independent event values, that’s why we use an individual type to describe each of them:

``` haskell
-- | Answer option selection.
data SelectAnswer
  = SelectAnswer
  { questionNumber :: Int
  , answerNumber :: Int }

-- | Payload for the event "show answers"
data CheckAnswers = CheckAnswers
```

## General Architecture

### Elm

Much has been said about the architecture of Elm applications — dozens of posts on the topic are available. However, we don’t use Elm at Typeable, so we cannot share our experience in this area but provide the reader with references to other sources:

* [ The Elm Architecture](https://guide.elm-lang.org/architecture/)
* [ Elm architecture on tutorialspoint](https://www.tutorialspoint.com/elm/elm_architecture.htm)
* [ The Elm Architecture](https://elmbridge.github.io/curriculum/The%20Elm%20Architecture.html) on ElmBridge

### Reflex

Despite the fact that Reflex doesn’t impose strict constraints on the architecture, it makes sense to follow some agreements on the code organization.

Our experience with Reflex has resulted in a certain pattern we will describe further.

_Let’s start with general considerations._

It’s rather convenient to separate the application representation (interface) and internal logic. But what exactly does the representation mean? Conceptually, the representation can be defined as the function that takes on the widget status (in case of Reflex, it’s dynamic, as it’s fully or partially “wrapped” in Dynamic) and returns an interface description and multiple events occurring during interaction with the interface.

The monad constrained by the `DomBuilder` is responsible for the “interface description”. Here and elsewhere we use `ObeliskWidget` constraint (from Obelisk) that includes the `DomBuilder`.

Thus, in a general case, the representation description in the form of a Haskell function could have the following type (for now, we don’t specify the type variables events and state):

```haskell
ui :: ObeliskWidget js t route m => state -> m events
```

The application logic will be implemented in another function, which, on the contrary, takes on multiple events and returns the dynamic status:

```haskell
model :: ObeliskWidget js t route m => events -> m state
```

To use them together, let’s declare an auxiliary high-order function, `mkWidget`:

```haskell
mkWidget :: ObeliskWidget js t route m
  => (events -> m state) -> (state -> m events) -> m ()
mkWidget model ui  = void (mfix (model >=> ui))
```

We used function `mfix` (a combinator of the fixed point for the monadic computation) with the type [`MonadFix`](https://hackage.haskell.org/package/base/docs/Control-Monad-Fix.html#t:MonadFix)`m => (a -> m a) -> m a`, as well as a combination of Kleisli arrows sometimes called just a fish:

```haskell
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)`
```

The division into UI and the “model” turns out to be rather convenient when you write dynamic widgets. You may notice the similarity between UI and the view in Elm, as well as between the “model” and the update. The difference is _how exactly_ we transfer the status and the events.

_Let's get back to our widget._

Let’s specify the state and events variables for our questionnaire widget.

According to the specification, there are only two events: the answer selection and clicking on the check button:

```haskell
data QuizEvents t = QuizEvents
  { selectAnswer :: Event t SelectAnswer
  , showAnswers :: Event t CheckAnswers }
```

The structure containing the dynamic data will be somewhat more complex:

```haskell
data QuizState t = QuizState
  { areAnswersShown :: Dynamic t AreAnswersShown
  , allQuestions :: [(QuestionText, [(Answer, Dynamic t IsChosen)])]
  , canCheckAnswers :: Dynamic t CanCheckAnswers
  , score :: Dynamic t Score }
```

We “wrap” in Dynamic only the status parts which may change. In particular, `allQuestions` field has only the value of `IsChosen` type “wrapped” in Dynamic. Of course, using a single Dynamic would allow writing a simpler code. But in this case, we would have had to rebuild even the static DOM parts.

This is another important difference between the two frameworks — in Reflex we control the DOM update ourselves, while the VDOM implementation built into Elm does this for us.


## Status Update

### Elm

Function update receives the message and the previous state and returns the new one:

```elm
update : Msg -> Model -> Model
update msg = case msg of
  SelectAnswer { questionNumber, answerNumber, isChosen } ->
    updateCanCheckAnswers <<
    ( mapAllQuestions
      <| updateAt questionNumber
      <| Tuple.mapSecond
      <| updateAnswers answerNumber isChosen )
  CheckAnswers -> mapAnswersShown (\_ -> AnswersShown) >> updateScore
```

We use auxiliary functions and the function composition operator (`>>`) to perform the status update in parts.

The rather awkward syntax used to update the fields of record types in Elm makes it necessary to declare manually such functions as `mapAnswersShown`, `mapAllQuestions` and the like, which just apply the function to the field value. In Haskell, we could use the lenses (refer to the [lens](https://hackage.haskell.org/package/lens) package and its analogs) generated automatically for each data type.

```elm
updateCanCheckAnswers : Model -> Model
updateCanCheckAnswers model =
  { model | canCheckAnswers =
    if List.all hasChosenAnswer model.allQuestions
    then CanCheckAnswers
    else CantCheckAnswers }

updateScore : Model -> Model
updateScore model =
  let
    hasCorrectAnswer (_, answers) =
      List.any isCorrectAnswerChosen answers
    correctAnswers =
      List.length <| List.filter hasCorrectAnswer model.allQuestions
    totalQuestions = List.length model.allQuestions
  in
    { model | score =
      Score { correctAnswers = correctAnswers
            , totalQuestions = totalQuestions } }

updateAnswers : Int -> IsChosen -> List (Answer, IsChosen) -> List (Answer, IsChosen)
updateAnswers answerIx newIsChosen =
  List.indexedMap <| \aix ->
    Tuple.mapSecond <| \isChosen ->
      if aix /= answerIx
      then
        if newIsChosen == Chosen
        then NotChosen
        else isChosen
      else newIsChosen
```


### Reflex

We form the dynamic status by receiving the widget events at the input and then saving all dynamic data in the fields of the returned `QuizState` value:

```haskell
mkQuizModel :: ObeliskWidget js t route m
  => [(QuestionText, [Answer])]
  -- ^ List of questions with answers
  -> QuizEvents t
  -> m (QuizState t)
mkQuizModel questions events = do
  areAnswersShown <- holdDyn AnswersHidden (showAnswers events $> AnswersShown)
  allQuestions <- mkAllQuestionsModel questions events
  canCheckAnswers <- mkCanCheckAnswersModel allQuestions
  score <- mkScoreModel areAnswersShown allQuestions
  return QuizState{..}
```

To this end, we use several combinators from [Reflex.Dynamic](https://hackage.haskell.org/package/reflex/docs/Reflex-Dynamic.html) module.

```haskell
holdDyn :: MonadHold t m => a -> Event t a -> m (Dynamic t a)
```

[`holdDyn`](https://hackage.haskell.org/package/reflex-0.8.0.0/docs/Reflex-Dynamic.html#v:holdDyn) is probably the easiest way of creating the Dynamic from the Event. Each time an event occurs, the values in the obtained Dynamic changes to the one contained in the event. At the same time, until the first event takes place, the Dynamic will contain the value we passed as the first argument.

Thus, dynamic value `areAnswersShown` will include the `AnswersHidden` until the event stored in field showAnswers occurs, and after that, it will change to `AnswersShown`.

In the auxiliary function `mkAllQuestionsModel` we perform iteration by the enumerated list of questions, and in the internal cycle – by the list of answers to each of them, in order to provide each of them with the dynamic status with `IsChosen` type:

```haskell
mkAllQuestionsModel :: ObeliskWidget js t route m
  => [(QuestionText, [Answer])]
  -- ^ List of questions with answers
  -> QuizEvents t
  -> m [(QuestionText, [(Answer, Dynamic t IsChosen)])]
mkAllQuestionsModel questions events = do
  for (enumerate questions)
    \(qNum, (questionText, answers)) -> do
    (questionText, ) <$> for (enumerate answers)
      \(aNum, Answer{..}) -> do
      let
        updChosenState SelectAnswer{questionNumber,answerNumber} isChosen = do
        guard (questionNumber == qNum)
        return
          if answerNumber == aNum
          then toggleChosen isChosen
          else NotChosen
      isChosenDyn <- foldDynMaybe updChosenState NotChosen
        (selectAnswer events)
      return (Answer{..}, isChosenDyn)
```

Expression `(questionText,)` is the syntax sugar for `(\x -> (questionText, x))`.

Combinator `foldDynMaybe` allows updating the Dynamic considering its previous status, as well as the event payload. Maybe allows omitting the update, if it is not required:

```haskell
foldDynMaybe :: (Reflex t, MonadHold t m, MonadFix m) => (a -> b -> Maybe b) -> b -> Event t a -> m (Dynamic t b)
```

Expression `foldDynMaybe updChosenState NotChosen (selectAnswer events)` creates the Dynamic that changes between the two values: `Chosen` and `NotChosen` in case a click on the answer option occurs.

The function used to update the status looks as follows:

```haskell
updChosenState SelectAnswer{questionNumber,answerNumber} isChosen = do
  guard (questionNumber == qNum)
  return
    if answerNumber == aNum
    then toggleChosen isChosen
    else NotChosen
```

We used `guard :: Alternative f => Bool -> f ()` to return `Nothing` (by doing so, we omit the Dynamic update — let’s remind that `Maybe` has the `Alternative` instance) in case the event is not related to the current question. Otherwise, we either change over value `IsChosen` or set it to `NotChosen`, if the other answer option was clicked. In this way, it is possible to select only one answer.

Further, in function `mkCanCheckAnswersModel` we form the dynamic value `CanCheckAnswers` that takes on value **Can**CheckAnswers only when every question has a selected answer (otherwise, it will be **Cant**CheckAnswers):

```haskell
mkCanCheckAnswersModel :: ObeliskWidget js t route m
  => [(QuestionText, [(Answer, Dynamic t IsChosen)])]
  -> m (Dynamic t CanCheckAnswers)
mkCanCheckAnswersModel allQuestions = holdUniqDyn do
  -- At least one answer was selected for each question
  allQuestionsAnswered <- all (Chosen `elem`) <$> do
    for allQuestions \(_, answers) -> do
     for answers \(_, dynIsChosen) -> dynIsChosen
  return if allQuestionsAnswered then CanCheckAnswers else CantCheckAnswers
```

Dynamic is in the Monad type class, which is why we can use the do notation.

It has to be noted that we don’t want to update `canCheckAnswers` value each time we choose an answer as this would cause a useless DOM rebuilding. We are interested only in the updates which really change the value. This is why we use [`holdUniqDyn`](https://hackage.haskell.org/package/reflex-0.8.0.0/docs/Reflex-Dynamic.html#v:holdUniqDyn) to deal with “unnecessary” updates:

```haskell
holdUniqDyn :: (Eq a, ...) => Dynamic t a -> m (Dynamic t a)
```

Constraint `Eq a` means that the equality check function must be defined for type `a`.

Similarly, we form the dynamic value `Score` that contains `NoScore` value, if the results have not been counted yet, or the results, in the opposite case.

```haskell
mkScoreModel :: ObeliskWidget js t route m
  => Dynamic t AreAnswersShown
  -> [(QuestionText, [(Answer, Dynamic t IsChosen)])]
  -> m (Dynamic t Score)
mkScoreModel areAnswersShown allQuestions = holdUniqDyn do
  areAnswersShown >>= \case
    AnswersHidden -> return NoScore
    AnswersShown -> do
    correctAnswers <- flip execStateT 0 do
      for_ allQuestions \(_, answers) -> do
      for_ answers \(answer, dynIsChosen) -> do
        isChosen <- lift dynIsChosen
        when (isChosen == Chosen && isCorrect answer == Correct) do
        modify (+ 1)
    return Score { correctAnswers, totalQuestions = length allQuestions }
```

Using the monad transformer [`StateT`](https://hackage.haskell.org/package/transformers/docs/Control-Monad-Trans-State-Lazy.html#t:StateT) allows describing the process of counting correct answers in a more “imperative” way.


## Rendering

### Elm

In Elm, rendering is rather obvious and needs no detailed explanation.

```elm
view : Model -> Html Msg
view model =
  div [] <|
  List.indexedMap (viewQuestion model.areAnswersShown) model.allQuestions ++
  [ div [ class "check-answers-button-container" ] [ viewFooter model ] ]

viewQuestion : AreAnswersShown -> Int -> (QuestionText, List (Answer, IsChosen)) -> Html Msg
viewQuestion areShown questionIx (question, answers) =
  div [class "question"] <|
    [ text question ] ++
    [ div [class "answers"]
    <| List.indexedMap (viewAnswer areShown questionIx) answers ]

viewAnswer : AreAnswersShown -> Int -> Int -> (Answer, IsChosen) -> Html Msg
viewAnswer areShown questionIx answerIx (answer, isChosen) =
  let
    events = [ onClick <|
               SelectAnswer { questionNumber = questionIx
                            , answerNumber = answerIx
                            , isChosen = toggleChosen isChosen
                            }]
    className = String.join " " <|
      ["answer"] ++
      ( if isChosen == Chosen
      then ["answer-chosen"]
      else [] ) ++
      ( if areShown == AnswersShown
        then ["answer-shown"]
        else ["answer-hidden"] ) ++
      ( if answer.isCorrect == Correct
        then ["answer-correct"]
        else ["answer-incorrect"] )
    attrs = [ class className ]
in
  div (attrs ++ events) [ text answer.answerText ]

viewFooter : Model -> Html Msg
viewFooter model =
  case model.score of
    NoScore ->
       case model.canCheckAnswers of
         CanCheckAnswers ->
           button [ onClick CheckAnswers ] [ text "Check answers" ]
         CantCheckAnswers ->
           div [ class "unfinished-quiz-notice" ]
               [ text "Select answers for all questions before you can get the results." ]
    Score { totalQuestions, correctAnswers } ->
      text <|
        "Your score: " ++ String.fromInt correctAnswers ++
        " of " ++ String.fromInt totalQuestions
```

We have fully described the widget. Now let’s get down to its initialization:

```elm
initialModel =
  { areAnswersShown = AnswersHidden
  , allQuestions = allQuestions
  , score = NoScore
  , canCheckAnswers = CantCheckAnswers
  }

main =
  Browser.sandbox { init = initialModel, update = update, view = view }
```

### Reflex

```haskell
quizUI :: ObeliskWidget js t route m => QuizState t -> m (QuizEvents t)
quizUI QuizState{..} = wrapUI do
  selectAnswer <- leftmost <$> for (enumerate allQuestions)
    \(qNum, (questionText, answers)) -> do
    divClass "question" do
      text questionText
    answersUI qNum areAnswersShown answers
  showAnswers <- footerUI canCheckAnswers score
  return QuizEvents{..}
```

Function [`leftmost`](https://hackage.haskell.org/package/reflex-0.7.1.0/docs/Reflex-Class.html#v:leftmost) allows combining several events of the same type into one.

```haskell
leftmost :: Reflex t => [Event t a] -> Event t a
```

It’s important to note that the events in Reflex can occur simultaneously. This is why it has to be kept in mind that it’s possible to lose something important, as in this case the leftmost ignores all events, except for the first one.

Here we use  leftmost to turn the list of events returned as the result of the iteration by the question list into one event. In this case, it’s not possible to click on two answer options simultaneously, so this is safe.

We also use  leftmost to create the answer list:

```haskell
answersUI :: ObeliskWidget js t route m
  => Int
  -> Dynamic t AreAnswersShown
  -> [(Answer, Dynamic t IsChosen)]
  -> m (Event t SelectAnswer)
answersUI qNum areAnswersShown answers = elClass "div" "answers" do
  leftmost <$> for (enumerate answers)
    \(aNum, (Answer{answerText,isCorrect}, dynIsChosen)) -> do
    event <- answerUI areAnswersShown answerText isCorrect dynIsChosen
    return (event $> SelectAnswer { questionNumber = qNum, answerNumber = aNum })
```

In function `answersUI` we iterate by the answers list, each time calling function answerUI, where we build a new Dynamic containing the [`Map`](https://hackage.haskell.org/package/containers/docs/Data-Map-Lazy.html#t:Map) from the dynamic attributes of the DOM, which is an answer option. We make use of the fact that the Dynamic is a monad to form the class name for an HTML element with an answer option. We use `Writer` for the sake of “imperativeness”.

We use `$> SelectAnswer { questionNumber = qNum, answerNumber = aNum }` to replace the empty value `()` (called “unit”), which is the payload of the “click” event by default, with the payload we need that shows the answer we clicked on.

```haskell
answerUI :: ObeliskWidget js t route m
  => Dynamic t AreAnswersShown
  -> AnswerText
  -> IsCorrect
  -> Dynamic t IsChosen
  -> m (Event t ())
answerUI areAnswersShown answerText isCorrect dynIsChosen =
  domEvent Click . fst <$> elDynAttr' "div" dynAttrs do
    text answerText
  where
    dynAttrs = do
    isChosen <- dynIsChosen
    areShown <- areAnswersShown
    let
      className = T.intercalate " " $ execWriter do
        tell ["answer"]
        when (isChosen == Chosen) $ tell ["answer-chosen"]
        tell [ if areShown == AnswersShown
                then "answer-shown"
                else "answer-hidden" ]
        tell [ if isCorrect == Correct
                then "answer-correct"
                else "answer-incorrect" ]
    return $ "class" =: className
```

Construction `domEvent Click . fst <$> elDynAttr'…` allows obtaining the click event in the form of a value.

`footerUI` is a widget containing either a text offering to answer all questions, or a check button, or the information on the results:

```haskell
footerUI :: ObeliskWidget js t route m
  => Dynamic t CanCheckAnswers -> Dynamic t Score -> m (Event t CheckAnswers)
footerUI canCheckAnswersDyn dynScore = wrapContainer do
  evt <- switchHold never <=< dyn $ do
    canCheckAnswers <- canCheckAnswersDyn
    score <- dynScore
    return if score /= NoScore
    then return never
    else case canCheckAnswers of
      CanCheckAnswers  -> checkAnswersButton
      CantCheckAnswers -> cantCheckNote
  dyn_ $ dynScore <&> \case
    NoScore -> blank
    Score{totalQuestions, correctAnswers} -> do
    text "Your score: "
    text . T.pack $ show correctAnswers
    text " of "
    text . T.pack $ show totalQuestions
  return (evt $> CheckAnswers)
  where
    wrapContainer = divClass "check-answers-button-container"
    checkAnswersButton = do
    domEvent Click . fst <$> do
      el' "button" do
      text "Check answers"
    cantCheckNote = do
    divClass "unfinished-quiz-notice" do
      text "Select answers for all questions before you can get the results."
    return never
```

Expression `switchHold never <=< dyn $ do …` can also be often seen in the code. We use it when we want to get an event from a dynamically changing widget.

_It makes sense to explain in detail what is going on here._

First of all, the correct way for placing the brackets is as follows: `(switchHold never <=< dyn) $ do…`

Let’s follow the types:

```haskell
switchHold :: ... => Event t a -> Event t (Event t a) -> m (Event t a)
never      :: ... => Event t a
(<=<)      :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c
dyn        :: ...  => Dynamic t (m a) -> m (Event t a)
```

* [`switchHold`](https://hackage.haskell.org/package/reflex-0.8.0.0/docs/Reflex-Class.html#v:switchHold) makes it possible to “switch” the events we are subscribed to as they become available. They are received as the payloads of another event. The event passed as the first argument is the one that will be active until the second event occurs.
* [`never`](https://hackage.haskell.org/package/reflex-0.8.0.0/docs/Reflex-Class.html#v:never) is just an event that never occurs.
* [`(<=<)`](https://hackage.haskell.org/package/base-4.14.1.0/docs/Control-Monad.html#v:-60--61--60-)is the fish we already know.
* [`dyn`](https://github.com/reflex-frp/reflex-dom/blob/ddf89778ed56373423fb38c6704a179278fdd49c/reflex-dom-core/src/Reflex/Dom/Widget/Basic.hs#L152) allows “using” a dynamic widget. The returned event activates each time the dynamic changes.

This implies that:

```haskell
switchHold never <=< dyn :: Dynamic t (m (Event t a)) -> m (Event t a)
```

It’s clear that at any point in time there will be a widget inside the Dynamic returning the event. This very widget will be “used”.

We use `if score /= NoScore then return never…` because if the result has been counted already, the event “count the result” must never occur.

A significant difference of the code shown above from the Elm code is that we return the events explicitly and don’t just assign them as the element attributes. The requirement to push the events through is the cost of the ability to process and combine them in any way anywhere we need. However, we don’t always do so in our production code. Sometimes, we can use the type class [`EventWriter`](https://hackage.haskell.org/package/reflex/docs/Reflex-EventWriter-Class.html) that offers the tellEvent function. tellEvent looks very much like the tell in a standard Writer:

```haskell
tellEvent :: EventWriter t w m => Event t w -> m ()
tell :: MonadWriter w m => w -> m ()
```

After fully describing the widget, we can make it operable using the function `mkWidget` created previously:

```haskell
mkQuizWidget :: ObeliskWidget js t route m => [(QuestionText, [Answer])] -> m ()
mkQuizWidget qs =
  mkWidget (mkQuizModel qs) quizUI
```

Widget preview:

![](https://blog.typeable.io/images/reflex-vs-elm/2.png)

# Conclusions

Elm’s advantages as compared with Reflex:

* The tooling is more convenient. Knowledge of Nix is not required; the Elm’s executable file provides everything you need to build the application.
* The language is simpler for a beginner. Elm is easy to learn as the first functional language.
* The compilation time, as well as the generated code are much shorter.
* You don’t need to divide the application status explicitly into the dynamic and static ones.

Drawbacks:

* Elm is a less expressive language. In comparison with Haskell, there is an increased need to duplicate the code due to the unavailability of such mechanisms as the type classes (for ad hoc polymorphism), template Haskell (for code generation), and [generics](https://wiki.haskell.org/Generics) (_Datatype-generic programming_, not to be confused with generics in OOP languages).
* The Model has to be rebuilt after each message. Even though persistent data structures in purely functional languages can be updated partially (sharing), the very fact that the framework doesn’t “see”, which portion of the data structure has been changed, makes it necessary to use the Virtual DOM.
* Elm [doesn’t support](https://guide.elm-lang.org/interop/limits.html) the foreign function interface to call arbitrary JavaScript functions.

Though Elm has several important advantages, we still opted for Reflex as it is rather convenient to use the same language both for the backend and frontend development.