Home

Awesome

concur-replica

CircleCI

Build interactive web UIs using nothing but Haskell.

No user-written JS. No transpiler.

How?!

Replica: a remote virtual DOM library. Clients run a fixed JavaScript snippet which opens a connection to your Haskell server. The client uses it to notify the server of browser events, and the server uses it to send DOM updates to be applied by the client.

Concur: a UI framework that reifies time and as such generalizes the Elm architecture. It's based around Widgets, sections of the UI that may return a value.

Upsides and downsides

This strategy is well understood due to its use by Phoenix LiveView (among other projects).

There are two situations where you should rule concur-replica out completely:

The strategy also has two softer costs:

Additionally, concur-replica is alpha software so it currently has additional deficiencies. Check the issue tracker for these, and they'll be fixed as it matures.

Despite these caveats however, concur-replica has incredible benefits. No JS! No REST API layer -- you can call whatever Haskell functions you want directly from your UI code. concur is an awesome way of making UIs. And you have the Haskell classics: STM is absolutely unfair for building collaborative apps, and UIs are so annoying to test that the type system really shines.

Obligatory counter example

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Concur.Core
import Concur.Replica

import Prelude hiding (div)

counter :: Int -> Widget HTML a
counter x = do
  click <- div []
    [ Left  <$> div [ onClick ] [ text "-" ]
    , text $ T.pack $ show x
    , Right <$> div [ onClick ] [ text "+" ]
    ]

  case click of
    Left _  -> counter (x - 1)
    Right _ -> counter (x + 1)

main :: IO ()
main = runDefault 8080 "Counter" (counter 0)

Projects using concur-replica

Running the examples

stack build
stack exec concur-replica-(calc|hilo|menu|misc|multi-entry|select|routing|website|chat)

Point your browser to http://localhost:8080 and behold the remote VDOM goodness.