Wednesday, November 16, 2016

Elm is a Funnny Language

I used Elm (a functional programming language for writing webapps), in a moderately complex project, and I enjoyed it.

Elm has a syntax similar to Haskell, but its semantic is much simpler because it has no classes.

This simplicity is a selling point of Elm, because I see Elm more like a replacement/competitor of JavaScript and its overwhelming ecosystem of libraries, than a competitor of Haskell. Elm semantic is more elegant and predictable than JavaScript, and it has few and more integrated libraries. So the passage from JavaScript to Elm has a lot of advantages from my point of view, and very few disadvantages.

On the contrary Elm can not replace a feature-rich and complex Haskell code-base, because Haskell is based on generic and reusable abstractions like Monoid, Functor, Monad, Traversable, but Elm can not support them without the class concept. Elm sticks to clasical functional programming: no classes, no ad-hoc polymorphism, but only generic functions like map, filter and so on.

Haskell is a general-purpose, multi-paradigm programming language, and you can choose between different type of architectures: e.g. functional reactive programming (FRP), software transactional memory (STM), applicative or monadic domain specific languages (DSL).

On the contrary Elm is laser focused on single-page webapps. For this domain, it enforces a common and fixed architecture, based on a Model, updated by asynchronous Commands and Tasks. After the changes, the view function converts the Model into elements of the user-interface. The Elm platform takes care of updating the user interface in an efficient and incremental way, without recomputing it from scratch, when small parts of the Model are changed. So in an Elm application you have only readable generative code, without low level details about incremental updates.

When you study an Elm application, you know in advance its architecture. This is an advantage respect Haskell (less different programming paradigms) and JavaScript (few and more integrated libraries).

This is an example of Elm code, that converts an ActiveExplosion value of the model, into an Svg value of the user-interface. In particular to a fading circle.

drawExplosion : Model -> Float -> ActiveExplosion -> Svg Msg
drawExplosion model activationTime e =
    let opacity = Basics.max 0.0 (1.0 - (currentTime - activationTime) / (e.deactivationTime - activationTime))
    in  Svg.circle [ cx (toString e.centerX)
                   , cy (toString e.centerY)
                   , r (toString 45.0)
                   , fill (model_fromColorToExplosionGradientId model e.color)
                   , fillOpacity (toString opacity)
                   ] []

Elm functional code can be used also for generating HTML and SVG documents. This is an Elm expression generating the NetRobots logo:

Svg.svg 
  [preserveAspectRatio "xMinYMin meet"
  , viewBox "0 0 350 75"
  , width "100%"
  ,  height "100%"]
  [ g [ Svg.Attributes.style "overflow:hidden; text-anchor: middle; font-size:45; font-weight: bold; font-family: Impact"]
      [text' 
         [ x "175"
         , y "55"
         , Svg.Attributes.style "fill: white; stroke: #0f9; stroke-width: 14"]
         [Svg.text "NetRobots"]
      , text' 
          [ x "175"
          , y "55"
          , Svg.Attributes.style "fill: white; stroke: #99f; stroke-width: 8"] 
          [Svg.text "NetRobots"]
      , text' 
          [ x "175"
          , y "55"
          , Svg.Attributes.style "fill: white; stroke: black; stroke-width: 2"] 
          [Svg.text "NetRobots"]
     ]
  ]

This is the generated SVG document:

<svg preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 75" width="100%" height="100%">
  <g style="overflow:hidden; text-anchor: middle; font-size:45; font-weight: bold; font-family: Impact">
    <text x="175" y="55" style="fill: white; stroke: #0f9; stroke-width: 14">NetRobots</text>
    <text x="175" y="55" style="fill: white; stroke: #99f; stroke-width: 8">NetRobots</text>
    <text x="175" y="55" style="fill: white; stroke: black; stroke-width: 2">NetRobots</text>
  </g>
</svg>

Elm expressions can be combined together, for factoring out repeated patterns, like in this case:

let netRobotsText strokeColor strokeWidth = 
      text' 
        [ x "175"
        , y "55"
        , Svg.Attributes.style ("fill: white; stroke: " ++ strokeColor ++ "; stroke-width: " ++ strokeWidth")]
        [Svg.text "NetRobots"]

in Svg.svg 
     [preserveAspectRatio "xMinYMin meet"
     , viewBox "0 0 350 75"
     , width "100%"
     ,  height "100%"]
     [ g [ Svg.Attributes.style "overflow:hidden; text-anchor: middle; font-size:45; font-weight: bold; font-family: Impact"]
         [ netRobotsText "#0f9" "14"
         , netRobotsText "#99f" "8"
         , netRobotsText "black" "2"]
     ] 

Summing up, Elm is useful only for writing single-page webapps, and it is:
  • simpler and more powerful than JavaScript
  • simpler but less powerful than Haskell

No comments:

Post a Comment