Porting my binary clock to Elm

Want to discuss the content of this article? Join the conversation on Twitter!

Binary clock in Clojurescript/Om

About a year ago I was playing with Clojurescript and Om, and made a small binary clock with it. You can read the original blog post here.

A couple of ports were created, in Reagent, and in Hoplon. Check them out!

Porting the same application to different languages or libraries/frameworks is a neat idea: it gives you a way to reason about different solutions of a problem, together with their inherent advantages and disadvantages. The most famous app in this category is perhaps TodoMVC.

Elm

Elm is a functional programming languange, related to Haskell. It compiles down to Javascript and is intended for interactive applications. Specifically it builds heavily on the idea of Functional Reactive Programming.

Surely it would be fun to port the binary clock to Elm!

Some Elm resources

I found the following links helpful.

Walkthrough

Firstly, the final result can be watched here, and the complete code is found on Github.

module BinClock where

import Graphics.Element (Element, container, midTop)
import Html (..)
import Html.Attributes (..)
import Signal
import Window
import List
import Bitwise
import Time (..)
import Date

The clock is made of cells. We have two kinds, the clock and the legend. The clock cells, cellCol, are empty, but have two different colors, if the bit is lit or not. The legend cells, cellVal, doesn’t have a background color, but instead contains a digit.

cellCol : Bool -> Html
cellCol bit =
    let color = if bit then "light" else "dark"
    in div [class ("cell" ++ " " ++ color)] []
    
cellVal : Int -> Html
cellVal digit = div [class "cell"] [text (toString digit)]

I kept the data representation pretty close to the Clojurescript original: a BitNum is a pair containing the digit it represents, and a list of Bool corresponding to the bit representation of the digit.

In turn, a column takes a BitNum and creates a list of cells for the bit representation, wrapped up in html markup.

type alias BitNum = (Int, List Bool)

column : BitNum -> Html
column (digit, bits) =
    let cells = (List.map cellCol bits) ++ [cellVal digit]
    in div [class "col"] cells

columns : List BitNum -> Html
columns cs =
    let cols = List.map column cs
    in div [class "colpair"] cols

legend : List Int -> Html
legend digits =
    let cells = List.map cellVal digits
    in div [class "col legend"] cells

We also need some code to take numbers, get the decimal parts, and create BitNum’s out of them:

decimalParts : Int -> List Int
decimalParts n = [n // 10, rem n 10]

toBitNum : Int -> BitNum
toBitNum n =
    let masks = List.map2 Bitwise.and [8, 4, 2, 1] (List.repeat 4 n)
        setp  = \x -> x > 0
        bits  = List.map setp masks
    in (n, bits)

The main view conclude the markup part were we crank everything together. It takes current Time as input and uses all of our markup parts to build the clock.

view : Time -> Html
view t =
    let conv = \x -> x |> decimalParts |> (List.map toBitNum)
        d = Date.fromTime t
        cols = [Date.hour d, Date.minute d, Date.second d]
               |> List.map conv
               |> List.map columns
    in div [] ([legend [8,4,2,1]] ++ cols)

I mostly borrowed the startup code from the TodoMVC example. Note that the main signal is augmented with Time, triggered every second.

main : Signal Element
main = Signal.map2 scene (every second) Window.dimensions

scene : Time -> (Int,Int) -> Element
scene t (w,h) =
    container w h midTop (toElement w h (view t))

That’s all, I hope you liked it!

Ports in other languages?

Wouldn’t it be cool to have ports in Purescript or GHCJS? Or maybe Idris or Funscript for that matter? Maybe I will. Or maybe you will? Let me know in any case.

If you have any comments or feedback, send me an email or send me a message on Twitter @lexicallyscoped.


←  Go Back