See what our members have been up to!
Today we learned how to get started with a Reflex and Reflex-Dom with Ali Abrar.
First, install Reflex platform.
$ git clone git@github.com:reflex-frp/reflex-platform.git
$ ./try-reflex
During the installation we chatted with Ali and Ryan (creator of ReflexFRP) to understand more about the background of this library and how it compares to other open source tools available.
There’s two parts: reflex, reflex-dom
Reflex gives frp functionalities. has datatypes (or building blocks) deals with interactive applications
Reflex-dom is a binding to web browsers api that is based on reflex. Takes callback driven, highly stateful thing that browser supports and turns it into reflex instead.
There are very few FRP dom specific comparisons for use in the browser. Elm is similar but not Haskell so you can’t use libraries found in Hackage.
Reactjs inspired approach is not purely frp, limited with inherent Javascript limitations.
The advantage of using ghcjs is that it gives you access to all of hackage. You can use any haskell library, and so with Reflex-Dom you have access on the front end to all the same stuff as backend applications.
Reflex itself can be used for a wide number of applications (websites, games, etc). Reflex-Dom can be used to produce javascript files. For example full stack web applications, or single web applications.
You can also use reflex-dom to create a native binary. Can produce web-gtk or similar variants, and also produce a distributable.
Here’s how you can look for documentation.
After everyone installed reflex-platform, we began with coding.
Step 1 Create a blank file: workshop.hs
Step 2 Imports import Reflex.Dom
at the top
Step 3 Write a main function
mainWidget will take over main body of html page.
Once you have mainwidget you can write the html DOM element widgets. The most basic widget is text
. Text is the lowest level. It won’t put it in a p tag or div tag or anything else. It is just plain text that is shown in the browser.
A page could be any level of complexity (login page, dashboard, etc.) but for now we start with compiling the basic text.
Step 4 In your Nix shell, type ghcjs workshop.hs
It creates a folder workshop.jsexe with a bunch of js files. Index.html just loads the javascript files that the compiler used. Open the html file in a browser and you’ll see what it produces. You can open up the chrome inspector to look at specific DOM tags produced.
Ghcjs can also work with the regular cabal system using cabal --configure ghcjs
. When using reflex-platform, it’ll be handled with nix by default so you can make a cabal file and edit the workon script to customize for the cabal file instead of the default file provided.
Tip: make reflex-platform a submodule in git so that the version is locked down. (similar to docker but more declarative) so that things may break but you’re not forced to update builds.
We’re going to use NASA’s api, available at https://api.nasa.gov/api.html#apod
Let’s design a login page with one text input for the API key.
Text Input with Reflex-Dom
textInput
returns a text input. it has a value, dynamic events (key press, focused, etc) but we’re only interested in the value right now. it’s a dynamic value. We read the docs and quickref to find out the type signatures.
_textInput_value
gives us back a Dynamic t String
type
dynText
takes a Dynamic String
and returns a dom element.
Adding this to the top ofy our file {-# LANGUAGUE ScopedTypeVariables #-}
lets us write the type signatures in workshop.hs.
Now with the api key input, we want a button also. Clicking on the button fires an event.
We include the button along with the text input on our form.
Compile this file with ghcjs workshop.hs
again.
Now we have defined a dynamic string and an event. When the event fires we want to take the string input and make a request with that value and need the feature that supports that. Looking at reflex quickref again…
tagDyn says it takes value of dynamic and an event to create another event. In our example, it takes the button clicking event to trigger the next event that we’ll define next.
what is t? t represents the timeline, it comes from math theory.
Working with API Requests
Now we want to construct a request with the NASA api. Ali reminds us again:
We want to draw a line between dots, something will change value when the button is clicked. We’re going to use holdDyn
in this example. It takes an initial value (a) and takes an event.
When do you use let vs <- binding when defining variables? You use let when defining values where as you bind monads. ConstDyn for example doesn’t have m so it’s not monadic.
When looking at quick ref, m
means you need an arrow thing. Another one is tagDyn doesn’t have monads (it’s a pure function) so you can use let. Results of a let doesn’t impact the reflex-dom program at all.
Tips:
- A monad is good for when you need a behavior.
- A pure function doesn’t have a side effect so it’s like text.
- At type level - bind arrow strips off monad. m() type: the bind gets rid of the m and gives you something.
Enter key pressed
Reacting to user interactions require dynamic events. Let’s look at reflex dom quick ref again to see the types.
We have two events that trigger something, but we only need one of them so we use a function that picks a default option from the pair. We use leftmost
to combine two events and returns one.
Tip: monoid basically lets you combine instances. unit
()
is also a monoid
<>
` says if you have 2 events and the thing inside is monoidal then you can treat inside as monoidal. If they fire simultaneously and will concatenate everything side.
Constructing API requests
xhr lets you construct a request. performRequestAsync
makes the xhr request, transforming the event to another event using a function with the xhr request inside. fmap
is the gold old fashioned fmap from where ever you might have learned it… so combining the two looks like the following:
We want _xhrResponse_responseText from XhrResponse so let’s convert the type. We’ll have to import data.text since it doesn’t come with prelude.
Tip: You can use ++ or <> to concatenate strings
We’re only interested in value if a response is returned, so we can make use of the Maybe type. fmap lets us apply functor to inside the event, event also has a maybe functor instance.
Parsing JSON
Finally, let’s use Aeson to parse json data. We only need FromJSON
type to decode. We can use decodeXhrResponse
from Reflex to decode the response.
show
will take value from something and turn it into some sort of string output
Tip If the aeson parser returns
Nothing
, it probably indicates a typo in the Nasapicture data type.
Tips: map, forMap map and formap are similar but different patterns, different order
import Data.Map
.. and sometimes you have to import bothData.Map (Map)
orData.Map as Map
Closing advice:
We are a registered non-profit group. Your donations are tax-deductible. To get more information about this, please contact us.