Posted by Gizra on Thu, 07/28/2016 - 00:00

I work at Gizra, so it was only a matter of time before Elm infected me as well, and I think it’s growing on me.

I wanted to build something a little different, not just the plain old TodoMVC. So, I harnessed every bit of creativity I had and came up with the most radical idea ever - I took the TodoMVC in Elm and got it to work in Electron, and called it Elmctron (I know, so creative of me).

Electron enables you to build cross platform desktop apps with web technologies. So we can take all the goodies we get with Elm and use them in our desktop application. It’s a brand new world!

It was my thought that we should build a couple of gulp tasks to make our life easier - to do the bare minimum because after all, who wants to do more than we he have to? (let’s hope my boss will not read this part)

So, with that in mind, the only commands I want to run are git clone .., npm install, and gulp. The gulp tasks should:

  • Compile SASS to css.
  • Compile Elm to JS.
  • Watch and auto-reload.
  • Automagically download and install elm packages.
  • Start the electron app.

Continue reading…

Posted by Brian Hicks on Mon, 07/25/2016 - 19:35

Elm is usually pretty clear, but there are certain things that are a little hard to search for.
One of those is the ! operator, introduced in 0.17.
What does it do?
Where does it come from?
And even more important, when should you use it?

Posted by theburningmonk.com on Mon, 07/18/2016 - 12:06

Tweet Hello, Recording of my Elm talk at Polyconf this year is available now.   Tweet

Posted by LambdaCat on Sun, 07/10/2016 - 23:15

So, Purescript.

If you know Elm and want to add to your toolset a language, which actually has those higher abstractions that you've heard about, Purescript is the obvious choice.

Purescript compiles to Javascript too, it can interoperate with any Javascript library, has no runtime, and has most of those

Posted by LambdaCat on Fri, 07/08/2016 - 18:34

I was supposed to give this talk at the July Cambridge DDD night, but I was ko'd by a bad flu, so I sent this video instead.

I did it while running a fever, but apparently it wasn't too bad, so here it is.

If any errors made it in,

Posted by LambdaCat on Sun, 07/03/2016 - 00:19

If you're familiar with Linux, you have certainly encountered pipes:

find / -name somename | grep ...

they take the result from one command and pass it to the next function, allowing you to chain multiple command together.

Road to Elm - Toc

They're helpful and convenient, and take advantage of the compositionality

Posted by LambdaCat on Sat, 07/02/2016 - 23:57

Chances are, if you've been reading Elm code older than a year, that you've seen a strange squiggly symbol <~.

It used to be exposed by the Signal namespace, but was then obsoleted in favour of just using its full name Signal.map (which is now itself obsolete).

in merge

Posted by Gizra on Thu, 06/16/2016 - 00:00

I’m going to give an Elm session in the next YGLF conf. This was a great excuse to free up some hours to work on a new v0.17 SPA (Single Page Application). You won’t believe what happened next…

Well, actually, you would: it was an awesome experience :)
In fact I’ve reached the point that the backend me is becoming jealous of frontend me.

View demo
Get the source code

Fetch GitHub user’s info on this fake login.

My goal with building this demo app, was to give a small, yet realistic, look into how Elm
allows us to accomplish daily tasks such as Http requests, routing, access, and more.
It was important for me to structure it in the same way that we structure larger apps built for production, so that it could demonstrate more effectively how Elm can be used in a project.

If you are interested in Elm, and want to get a feeling of how it could be built for your apps, this might be a good starting point. I’ve even wanted to add a single test to show how that could be done. But Elm being such a fun, predictable, opinionated, and fun (no mistake here, it deserves the double fun) to work with, I’ve ended up adding more and more tests.
Isn’t that yet another great sign for Elm? I was adding unit tests for a demo app, while we hardly added any unit tests for our Angular apps in production!

I was holding myself from adding too many features, but I couldn’t resist polishing the existing ones, and adding lots of comments. With the compiler’s tough love and ever growing unit tests, any change was
so easy it almost felt like cheating (and note that I rarely write “easy” or “trivial” on development issues).

Continue reading…

Posted by Rundis on Mon, 06/13/2016 - 01:00

The last few years I’ve worked on projects using Groovy and Clojure/ClojureScript.
In 2016 I’ve spent quite a bit of pastime trying to get to grips
with statically typed functional languages. In particular I’ve deep dived into Elm. I’ve also dipped
my toes into Haskell. It’s been a great learning experience and has changed my view of static typing.
Does this mean I’m a static typing zealot now ? Nah, but there is no doubt I’m much more open to the benefits of static typing.
I guess would characterize myself more like undecided or confused than convinced either way.

Background

A couple of years ago I started working with Groovy (and Grails). I fell in love
and felt I became way more productive than I had ever been when working with Java. I rarely
missed the added type safety of Java. Groovy also gave me a gentle introduction to functional programming related concepts in a way Java never encouraged me to.

In 2014 I started dabbling with Clojure(Script), but it took until 2015 before I got a chance
to use it for real in a project. It was a blast and I finally started to understand why more and more people
are turning towards functional programming. Clojure/ClojureScript became a big part of my life
both at work and evenings and nights. I was hooked.

At the end of last year I was back on a Groovy/Grails project. I was perfectly ok with that, but it wasn’t
a shiny new thing any longer, so I guess that’s partially why I was looking for something new to learn on the side.
Elm really caught my attention. When I watched Let’s be mainstream! User focused design in Elm
I finally found a statically typed functional language that looked approachable to me.

First signs of functional immutable damage

My time with Clojure (and gradually Elm) had changed me. I started to change how I coded Groovy. I tried to be more
functional and whenever I declared a variable that I later mutated I was left feeling dirty somehow.
It’s hard to try to enforce immutability in Groovy when the language, libraries and idioms don’t make immutability
a first class citizen. I had to bite the bullet quite a few times, and yeah I could still get things done.
The thing is, I started to pay more attention to what kind of errors and bugs I introduced as a result of careless mutation.

One particular example springs to mind. I was doing validation of a master/detail form.
To validate the detail rows of the form I needed to make sure they were sorted.

Easy peasy ?

master.detailRows.sort {it.date}

However this had the nasty side-effect
of reordering the detail rows in my UI which was rendered from this object.
I was puzzled at first, but then I remembered that immutability is not something you
can take for granted in the Groovy collection API (some things are, others are just bolted on top of Java).
The fix was easy enough. collection.sort has an overloaded version that takes a boolean parameter mutate.

So I was left with

master.details.sort(false) {it.date}

My eyes hurt: sort false, but but I do want to sort.
2 years ago I wouldn’t think much of this, it’s just a thing I was used to deal with and spend cycles on.
Now I get annoyed both with myself for forgetting and the language for making me feel dumb for not remembering.

Adding types

After having spent some time with Elm (and Haskell) I noticed I started to add more
type information in my Groovy code. I felt it improved the readability of my functions and methods.
It also made IntelliJ more happy and helpful in many cases.
The frontend of the application is written in JavaScript with a fair chunk of jQuery. Introducing something like Flow
might be helpful, but I’m convinced there are other more fundemental issues that needs to be addressed before considering that.

I’m pretty sure I’ll be using something like Schema more actively when writing Clojure/ClojureScript
going forward. When I have the chance Clojure Spec will probably be the preferred option. I know it’s not static typing, but my hunch is
that it will have a huge positive impact on documentation, error messages, runtime checks, testing and probably many other things too.

Functionally dynamic, but statically aware

This week I was back to a Clojure/ClojureScript project again. I’m quite excited and I’m convinced I’m going to have a blast.
However I’ve decided to use this opportunity to reflect more on where I feel Clojure/ClojureScript with it’s dynamic typing shines and where I think
static typing might have been helpful. After spending so much time with Elm and very much enjoying it, I might be susceptible to confirmation bias that static typing only carries benefits.
I’m going to try real hard to stay as objective or rather true to myself as I can when reflecting on positives of static vs dynamic.
Of course there’s a lot more to languages than static vs dynamic typing. I do find it interesting to reflect about it though, especially
since so many people seem to have such strong opinions about type safety. I myself am mostly confused or largely undecided at the moment.

First week reflections

Undoubtably with some Elm tinted glasses

The good

  • Figwheel how I’ve missed you ! With the latest release, error messages has gotten way better too. Maybe Elm with it’s suberb error messages has been an inspiration ?
  • I haven’t gotten my tooling set up right yet, but know that once I’ve got the REPL stuff set up right I’m going to be a happier puppy
  • The app is really cool, and there are lots of exciting techs to dig into
  • Paredit rocks for editing

Unsure/unknowns

  • re-frame - When I first read about it several months ago I was initially convinced that this
    small but very powerful framework was a fantastic thing. Maybe it really is to. But having experienced Elms departure from FRP, I’m wondering whether it might have some drawbacks at scale that I am not aware of yet.
    I’ve barely gotten a chance to work with it, but I’ve so far found it hard to internalize all the reactive dataflows going on in the client app. I obviously need to spend more time before making any judgment.
    Maybe I’ll write a blog post comparing The Elm Architecture to re-frame in the future.

Have I become dumber ?

  • I genuinly found it harder than before to understand what various functions did by looking at their signature.
    That could very well be down to naming and lack of documentation and or something like schema, but it was initially frustrating to see functions with map parameters and having to read through
    the whole of the implementation to get an understanding of what they might contain. println to the rescue…​ sort of.
  • I made silly mistakes, some of these resulted in things just not happening and others resulted in stacktraces that wasn’t helpful in anyway at all.
    I can’t help but think about the fact that static types and a helpful compiler would have prevented me from making many of those mistakes. Sure I should have tested more, both through the use of the REPL and probably more proper tests too.
  • I was faced with a few refactorings, that didn’t really go as well as I feel it should have. Again more tests would have helped, but then again a lot of those tests I just wouldn’t have needed to write in Elm.

An attempt to summarize

I’m convinced that functional programming vs imperative programming is a much more important concern than
static vs dynamic typing. I’m also in no doubt that I think functional programming is by far superior.
A year ago I was solidly in the dynamic typing camp. My impression of statically typed functional languages was that they were way to hard to get started with.
None of the languages I had heard about seemed particularily approachable and I had doubts about their practicality for the problems
I typically encounter in my projects. I’ve tried Haskell a couple of times, but I guess I was never commited enough.
Learning Elm has not only been great fun, but It has clearly opened my mind to the possibility that static type checking can be very beneficial.
It’s hard to describe the experience of doing a major refactoring, having a really helpful and friendly compiler guide you along step by step and when finally
everything compiles it just works. Having had that experience many times with Elm (and to a degree Haskell) certainly changed something fundementally in my thinking.

Until I have used Elm, Haskell or another statically typed functional language in a real project I’m in no position to pass any proper (personal) judgement. Maybe
I’m just going to remain confused, or maybe I’m never going to have a particularily strong preference.

Posted by Rundis on Mon, 05/30/2016 - 01:00

Elm version 0.17 was released a few weeks back. If haven’t already, you should read the annoucement post
A Farewell to FRP. So what does that mean for the Albums app ?
Sounds like we’re in for a massive rewrite. It turns out, since we were already using The Elm Architecture to
structure our application, the impact isn’t that big after all. Most of it is mechanical, and actually the biggest change
is that we can no longer use the 3.rd party routing library we depended on.

Useful resources

  • Check out the other episodes in this blog series.
  • The accompanying Albums sample app is on github, and there is a tag
    for each episode

Table of Contents

Introduction

I would have done the upgrade to 0.17 sooner, but the Album application depended on a 3rd party package
called elm-transit-router. It served us well and we even got some nice
transition animations when changing pages. However as all the routing libraries that we’re available for 0.16, it
depended on a community package called elm-history. That package was never going to updated to support 0.17, in fact
all support for the Web Platform APIs will eventually supported by the Elm language.

Last week Navigation was announced. This is library for managing navigation in a SPA. It provides nice abstractions over the History API.
In tandem Evan released URL Parser which is a simple parser for turning URLs into structured data.

With that in place I felt confident we should be able to do the upgrade. Let’s walk through the highlights !

Upgrade steps

Upgrading packages

Table 1. /frontend/elm-package.json

0.17
0.16

"dependencies": {
"elm-community/elm-json-extra": "1.0.0 <= v < 2.0.0",
"elm-community/list-extra": "2.0.0 <= v < 3.0.0",
"elm-lang/core": "4.0.0 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"elm-lang/navigation": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0",
"evancz/url-parser": "1.0.0 <= v < 2.0.0"
},
"elm-version": "0.17.0 <= v < 0.18.0"

"dependencies": {
"circuithub/elm-list-extra": "3.9.0 <= v < 4.0.0", (1)
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"etaque/elm-route-parser": "2.1.0 <= v < 3.0.0",
"etaque/elm-transit-router": "1.0.1 <= v < 2.0.0", (2)
"etaque/elm-transit-style": "1.0.1 <= v < 2.0.0",
"evancz/elm-effects": "2.0.1 <= v < 3.0.0", (3)
"evancz/elm-html": "4.0.2 <= v < 5.0.0", (4)
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.2 <= v < 3.0.0" (5)
},
"elm-version": "0.16.0 <= v < 0.17.0"

1
Elm Community have taken over this package

2
elm-transit-router, elm-route-parser, elm-transit-style have been replaced by elm-lang/navigation and evancz/url-parser
(pls note you can still use etaque/elm-route-parser with the navigation package if you need more advanced route parsing)

3
This package has been baked into core of Elm for 0.17, so this package is no longer needed

4
This package has moved under the elm-lang umbrella. So has it’s low level virtual-dom transitive dependency

5
This package has basically been moved into elm-lang/html

Mechanical changes

Module declarations

In 0.16 we had

module Main (..) where

In 0.17 we have

module Main exposing (..)

Luckily Elm Format handles this conversion automatically for us when we do format of an 0.16 .elm file !
So we can just run elm-format on the src directory.

Effects are now named Cmd

The new name for Effects are now Cmd shorthand for Command. Cmd is part of elm-lang/core
and lives in the Platform.Cmd module

Table 2. Changes to a typical update function

0.17
0.16

type Msg
= SomeMsg
| SomeOtherMsg

update : Msg -> Model -> ( Model, Cmd Msg ) (1)
update msg model =
case msg of
SomeMsg ->
( { model | count = model.count + 1 }
, Cmd.none (2)
)
-- etc...

1
You’ll also notice that Action has changed to Msg. It’s just a naming convention change
, but it better conveys what it actually is. You’ll see later when we get to the view function why it’s probably a good idea for you to
follow that convention.

2
As you see, here it’s just a naming change in practice

type Action
= SomeAction
| SomeOtherAction

update : Action -> Model -> ( Model, Effects Action )
update action model =
case action of
SomeAction ->
( { model | count = model.count + 1 }
, Effects.none
)
-- etc...

Making these changes is also fairly trivial with a good old search/replace.

Mailbox and address are gone in 0.17

Table 3. Changes to a typical view function

0.17
0.16

view : Model -> Html Msg (1)
view model =
button
[ onClick SomeMsg ] (2)
[ text "DoStuff" ]

view : Signal.Address Action -> Model -> Html
view address model =
button
[ onClick address SomeMsg ]
[ text "DoStuff"]

  1. The address parameter is gone, you no longer need to concern yourself with the intricacies of mailboxes.
    But you’ll also notice that the return value type Html takes a tag which in this case is our Msg type. So if we have any event handlers
    in our view code, we are telling it that those should result in a message of type Msg. We’ll come back to this in a bit more detail when we go through a nesting example.
  2. We no longer need to deal with an address for our event handler, we just tell Elm that when the user clicks the button, it should
    trigger our update function with the given Msg SomeMsg. The Elm runtime will take care of routing the message to our update function without any address mumbojumbo !

Again making this change is largely a matter of search/replace. There are a few exceptions though.

Table 4. on "input" is now luckily onInput !

0.17
0.16

[ input
[ class "form-control"
, value model.name
, onInput SetAlbumName
]
[]
]

[ input
[ class "form-control"
, value model.name
, on "input"
targetValue
(\str -> Signal.message address (SetAlbumName str))
]
[]
]

But let’s say you actually do need a custom decoder it would still be simpler than in 0.16

import Json.Decode as Json

-- ...

[ input
[ class "form-control"
, value model.name
, on "input" (Json.map SetArtistName targetValue) (1)
]
[]
]

1
Here we just map over the targetValue, and call SetArtistName with the value. targetValue is a Json decoder which picks out the value from our input field when the event is triggered

Routes and Route parsing (ehh…​ URLs if you like)

Table 5. Route definitions

0.17
0.16

type Route
= Home
| ArtistListingPage
| ArtistDetailPage Int
| NewArtistPage
| AlbumDetailPage Int
| NewArtistAlbumPage Int

type Route
= Home
| ArtistListingPage
| ArtistDetailPage Int
| NewArtistPage
| AlbumDetailPage Int
| NewAlbumPage
| NewArtistAlbumPage Int
| EmptyRoute

So the only change here is basically the removal of a couple of routes that weren’t in use.

Table 6. Route parsing

0.17 (url-parser)
0.16 (elm-route-parser)

routeParser : Parser (Route -> a) a
routeParser =
oneOf
[ format Home (s "")
, format NewArtistPage (s "artists" </> s "new")
, format NewArtistAlbumPage
(s "artists" </> int </> s "albums" </> s "new")
, format ArtistDetailPage (s "artists" </> int)
, format ArtistListingPage (s "artists")
, format AlbumDetailPage (s "albums" </> int)
]

decode : Location -> Result String Route
decode location =
parse identity routeParser (String.dropLeft 1 location.pathname)

routeParsers : List (Matcher Route)
routeParsers =
[ static Home "/"
, static ArtistListingPage "/artists"
, static NewArtistPage "/artists/new"
, dyn1 ArtistDetailPage "/artists/" int ""
, dyn1 AlbumDetailPage "/albums/" int ""
, static NewAlbumPage "/albums/new"
, dyn1 NewArtistAlbumPage "/artists/" int "/albums/new"
]

decode : String -> Route
decode path =
RouteParser.match routeParsers path
|> Maybe.withDefault EmptyRoute

The parsing syntax is slightly different, but the transition was fairly trivial in our case.
The observant reader will notice that we’ve skipped over the case when there is not matching route.
We’ll get back to that when we wire it all together.

Encoding

encode : Route -> String
encode route =
case route of
Home ->
"/"

ArtistListingPage ->
"/artists"

NewArtistPage ->
"/artists/new"

ArtistDetailPage i ->
"/artists/" ++ toString i

AlbumDetailPage i ->
"/albums/" ++ toString i

NewArtistAlbumPage i ->
"/artists/" ++ (toString i) ++ "/albums/new"

Encoding routes is pretty much exactly the same as before.

Table 7. Handy helpers

0.17 (url-parser)
0.16 (elm-route-parser)

navigate : Route -> Cmd msg (1)
navigate route =
Navigation.newUrl (encode route)

linkTo : Route -> List (Attribute msg) -> List (Html msg) -> Html msg
linkTo route attrs content = (2)
a ((linkAttrs route) ++ attrs) content

linkAttrs : Route -> List (Attribute msg)
linkAttrs route =
let
path =
encode route
in
[ href path
, attribute "data-navigate" path (3)
]

catchNavigationClicks : (String -> msg) -> Attribute msg
catchNavigationClicks tagger = (4)
onWithOptions "click"
{ stopPropagation = True
, preventDefault = True
}
(Json.map tagger (Json.at [ "target" ] pathDecoder))

pathDecoder : Json.Decoder String (5)
pathDecoder =
Json.oneOf
[ Json.at [ "data-navigate" ] Json.string
, Json.at [ "parentElement" ] (lazy (\_ -> pathDecoder))
, Json.fail "no path found for click"
]

1
A couple of places in the Album app we wish to be able to navigate to a new page as a result of some logic
in the update function is some component. Tbh we might be better off inlining this
in the relevant update functions.

2
This is a handy convenience function for creating a link to one of our defined routes (aka pages in our App)

3
In addition to the href attribute we define a data-navigate attribute which we can use for a catch all handler we’ll come to in a second

4
This function allows us to catch all link clicks for a given element and all it’s child elments.
It prevents the browser from making the url reguest and rather allows us to provide a custom tagger function that receives the Url in question and can create a message as a result.
It will make more sence to you when you see how it’s used in our Main module later on.

5
A Json parser which will recursivly walk through the element tree for the node receiving the event and try to find an element with the data-navigage attribute defined.

redirect : Route -> Effects ()
redirect route =
encode route
|> Signal.send TransitRouter.pushPathAddress
|> Effects.task

clickAttr : Route -> Attribute
clickAttr route =
on "click" Json.value (\_ -> Signal.message TransitRouter.pushPathAddress <| encode route)

linkAttrs : Route -> List Attribute
linkAttrs route =
let
path = encode route
in
[ href path
, onWithOptions
"click"
{ stopPropagation = True, preventDefault = True }
Json.value
(\_ -> Signal.message TransitRouter.pushPathAddress path)
]

I borrowed most of this code from The tacks application from @etaque. Kudos to @etaque for coming up with this !

Please be adviced that these helpers do make a compromise in terms of type safety.
I’m sure in due time, more type safe patterns will emerge. An obvious alternative to this approach is to
have a custom message in each update function that handles navigation. I’m going to try that out in the near future and see how it plays out.

Sample usage

Let’s have a quick look at a few examples on how we are using the navigate and linkTo helper functions
in the Albums app. How it all fits together will hopefully be apparent when we describe how we wire everything together in our Main module a little later on

Table 8. artistRow function in frontend/src/ArtistDetails.elm

0.17
0.16

artistRow : Artist -> Html Msg
artistRow artist =
tr []
[ td [] [ text artist.name ]
, td []
[ Routes.linkTo (Routes.ArtistDetailPage artist.id) (1)
[ class "btn btn-sm btn-default" ]
[ text "Edit" ]
]
, td []
[ button
[ class "btn btn-sm btn-danger"
, onClick <| DeleteArtist (.id artist) (2)
]
[ text "Delete!" ]
]
]

1
Here we are creating a normal link using the helper function described earlier. The result of clicking it should just be navigation, so sending a message to the ArtistListing update function which then creates the navigation effect feels like it might be to much work/boilerplate

2
Here the primary thing we want to handle is not navigation, the primary concern is handling deletion so we follow the normal pattern of returning a Msg which will be routed to our update function for handling

artistRow : Signal.Address Action -> Artist -> Html
artistRow address artist =
tr
[]
[ td [] [ text artist.name ]
, td
[]
[ button
[ class "btn btn-sm btn-default"
, Routes.clickAttr
<| Routes.ArtistDetailPage artist.id
]
[ text "Edit" ]
]
, td
[]
[ button
[ class "btn btn-sm btn-danger"
, onClick address (DeleteArtist (.id artist))
]
[ text "Delete!" ]
]
]

Table 9. update function in frontend/src/ArtistDetail.elm

0.17
0.16

-- ...

HandleSaved artist ->
( { model
| id = Just artist.id
, name = artist.name
}
, Routes.navigate Routes.ArtistListingPage (1)
)
-- ...

1
Upon successfully saving an artist to our backend service, we create a Cmd (aka request for an effect to be performed), using our util function, to route the user to the
ArtistListingPage

HandleSaved maybeArtist ->
case maybeArtist of
Just artist ->
( { model
| id = Just artist.id
, name = artist.name
}
, Effects.map (\_ -> NoOp)
(Routes.redirect Routes.ArtistListingPage)
)

Nothing ->
Debug.crash "Save failed... we're not handling it..."

Dealing with Http

So in our Album app we separated all HTTP requests to a separate module we called ServerApi.
The changes from 0.16 to 0.17 isn’t massive, but since we’re at it we might as well make some small improvements
to be better prepared for error handling in future episodes.

0.17
0.16

getArtist :
Int
-> (Http.Error -> msg)
-> (Artist -> msg)
-> Cmd msg
getArtist id errorMsg msg =
Http.get artistDecoder
(baseUrl ++ "/artists/" ++ toString id)
|> Task.perform errorMsg msg

getArtist : Int -> (Maybe Artist -> a) -> Effects.Effects a
getArtist id action =
Http.get artistDecoder (baseUrl ++ "/artists/" ++ toString id)
|> Task.toMaybe
|> Task.map action
|> Effects.task

The http methods haven’t really changed, but the manner in which we request the runtime to perform them have changed.
We no longer have the Effects package, so we need to use Task.perform to do it now. Our 0.16 implementation used
Maybe to signal success or failure, in 0.17 we have opted to give a different message for success or failure.
So if getArtist fails the error result of or http action will be passed to our update function wrapped in the provided Msg given by our errorMsg param,
if it succeeds the response will be json decoded and passed to our update function wrapped in the provided Msg given by our msg param.

Separating out all our http requests in one module gives flexibility in usage from multiple modules, but comes with a price of reduced type safety though.
You might want to localize http stuff with your components to make them more self-contained.

Usage Comparison

frontend/src/AlbumDetail.elm 0.16

update : Action -> Model -> ( Model, Effects Action )
update action model =
case action of
NoOp ->
( model, Effects.none )

GetAlbum id ->
( model
, Effects.batch
[ getAlbum id ShowAlbum
, getArtists HandleArtistsRetrieved
]
)

ShowAlbum maybeAlbum ->
case maybeAlbum of
Just album ->
( createAlbumModel model album, Effects.none )

Nothing -> -- TODO: This could be an error if returned from api !
( maybeAddPristine model, getArtists HandleArtistsRetrieved )

HandleArtistsRetrieved xs ->
( { model | artists = (Maybe.withDefault [] xs) }
, Effects.none
)

Our use of Maybe to signal failure in our 0.16 implementation clearly muddles what’s going on in terms of potential failures.

frontend/src/AlbumDetail.elm 0.17

mountAlbumCmd : Int -> Cmd Msg (1)
mountAlbumCmd id =
Cmd.batch
[ getAlbum id FetchAlbumFailed ShowAlbum
, getArtists FetchArtistsFailed HandleArtistsRetrieved
]

mountNewAlbumCmd : Cmd Msg (2)
mountNewAlbumCmd =
getArtists FetchArtistsFailed HandleArtistsRetrieved

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
-- TODO: show error
FetchAlbumFailed err -> (3)
( model, Cmd.none )

ShowAlbum album -> (4)
( createAlbumModel model album, Cmd.none )

HandleArtistsRetrieved artists' ->
( { model | artists = artists' }
, Cmd.none
)

-- TODO: show error
FetchArtistsFailed err ->
( model, Cmd.none )

-- rest left out for brevity

1
This command has been separated out as an exposed function for the module. The reason is that we need to perform this
when we navigate to a `/albums/<id>. I.e when that particular url is mounted. You’ll see how when we cover the Main module.
We are actually running two http requests here.. hopefully/presumably in the order they are listed :-)

2
Similar to the above, but this is for handling when the user navigates to the url for creating a new album

3
if getAlbum should fail this is where we should handle that (And we will eventually in a future episode)

4
If getAlbum succeeds we set the model up for displaying the retrieved artist

Nesting Components

The way you handle nesting of components in 0.17 has changed (for the better) with the removal of Mailboxes.
If you didn’t do to much fancy stuff with addresses the transition to 0.17 should be quite straight forward.
We’ll illustrate by showing a simple/common transition and then we will show how you might handle a more complex
nesting scenario (based on actual examples from the Albums App)

The common scenario

Table 10. update function in frontend/src/Main.elm

0.17
0.16

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
HomeMsg m ->
let
( subMdl, subCmd ) =
Home.update m model.homeModel
in
{ model | homeModel = subMdl }
! [ Cmd.map HomeMsg subCmd ] (1)
-- ...

1
So rather than using Effects.map to map the result action(s) of effects from a child component, we use Cmd.map to map result msg(s) from a child component
to a Msg that is known to the parent module.

update : Action -> Model -> ( Model, Effects Action )
update action model =
case action of
HomeAction homeAction ->
let
( subMdl, effects ) =
Home.update homeAction model.homeModel
in
( { model | homeModel = subMdl }
, Effects.map HomeAction effects
)

-- ...

I think you’ll agree this change is pretty simple to deal with. Let’s see how nesting of view functions
for components have changed

Table 11. contentView function in frontend/src/Main.elm

0.17
0.16

contentView : Model -> Html Msg
contentView model =
case model.route of (1)
Home ->
App.map HomeMsg (2)
<| Home.view model.homeModel

-- ...

1
As we did in 0.16 we keep track of the current route in our model

2
App.map is shorthand for Html.App.map. So we need to map between the Msg type returned from the view function in the Home module
to a Msg type that is known to our Main module. In this instance it’s HomeMsg. We need to do this mapping so that when the msg is passed
pack into our root update function we know which msg we should forward to which subcomponent.

contentView : Signal.Address Action -> Model -> Html
contentView address model =
case (TransitRouter.getRoute model) of
Home ->
Home.view (Signal.forwardTo address HomeAction) (1)
model.homeModel

1
Signal.forwardTo essentially achieved the same effect, but it’s way less intuitive to grasp. It’s unlikely you’ll miss it much !

This change isn’t quite search/replace (well with regex perhaps), but it’s quite trivial too.
Ok let’s move onto something a bit more complex.

A more complex scenario - Album and tracks

If you wish to see the Album and Tracks solution in action, you can check it out here:

Table 12. update function in frontend/src/TrackRow.elm

0.17
0.16

type Msg
= SetTrackName String
| SetMinutes String
| SetSeconds String
| Dispatch DispatchMsg (1)

type DispatchMsg (2)
= MoveUp
| MoveDown
| Remove

update : Msg -> Model -> ( Model, Maybe DispatchMsg ) (3)
update msg model =
case msg of
SetTrackName v ->
( { model | name = v, status = Modified }
, Nothing (4)
)

SetMinutes str ->
-- ...

SetSeconds str ->
-- ...

Dispatch dispatchMsg -> (5)
( model, Just dispatchMsg )

1
We add a new Msg tag called Dispatch which has a payload of type DispatchMsg to model
messages we would like to notify the parent of this component to handle

2
DispatchMsg becomes part of the public Api for our component so we need to expose it from our module

3
The way we notify the parent in this solution is to add a return value, so now we return a tuple of Model and Maybe a DispatchMsg the parent
should respond to.

4
For the component internal messages there is nothing extra the parent should respond to, so we simply return Nothing as a DispatchMsg

5
For all dispatch messages we return the concrete dispatch message tag that we want the parent to handle

type Action
= SetTrackName String
| SetMinutes String
| SetSeconds String

update : Action -> Model -> Model
update action model =
case action of
SetTrackName v ->
{ model | name = v, status = Modified }

SetMinutes str ->
-- ..

SetSeconds str ->
-- ..

There is no magic involved here, we are just returning an additional piece of info in the return value of
our update function.

Table 13. view function in frontend/src/TrackRow.elm

0.17
0.16

view : Model -> Html Msg
view model =
tr []
[ td [] [ statusView model ]
, td [] [ moveView model ]
, td [] [ nameView model ]
, td [] [ durationView model ]
, td [] [ removeView model ]
]

removeView : Model -> Html Msg
removeView model =
button
[ onClick (Dispatch Remove) (1)
, class
<| "btn btn-sm btn-danger "
++ if isPristine model then
"disabled"
else
""
]
[ text "Remove" ]

-- ...

1
When the user clicks the remove button, we simply return a Msg with the tag Dispatch carrying a DispatchMsg with the tag Remove
This msg will be routed through the top-level update function, through the update function in AlbumDetailPage and finally to the update function in TrackRow.
There it will be handled by the Dispatch dispatchMsg → case and simply returned to the parent (AlbumDetailPage)

type alias Context = (1)
{ actions : Signal.Address Action
, remove : Signal.Address ()
, moveUp : Signal.Address ()
, moveDown : Signal.Address ()
}

view : Context -> Model -> Html
view context model =
tr
[]
[ td [] [ statusView model ]
, td [] [ moveView context model ]
, td [] [ nameView context model ]
, td [] [ durationView context model ]
, td [] [ removeView context model ]
]

removeView : Context -> Model -> Html
removeView context model =
button
[ onClick context.remove () (2)
, class <| "btn btn-sm btn-danger "
++ if isPristine model then
"disabled"
else ""
]
[ text "Remove" ]

-- ..

1
In our 0.16 implementation we used this funny type and made it part of the public Api
as an extra param to the view function.

2
This looks super-weird to someone who doesn’t intuitively know that () is Unit.
onClick takes 2 parameters an address and an Action. In this case context.remove is the first param and () is the second !
There is little point in explaining further, let’s just agreed that this isn’t very intuitive ?

0.16 implementation of update function in frontend/src/AlbumDetail.elm

update : Action -> Model -> ( Model, Effects Action )
update action model =
case action of
-- ...

RemoveTrack id ->
( { model \| tracks = List.filter (\( rowId, _ ) -> rowId /= id) model.tracks }
, Effects.none
)

MoveTrackUp id ->
-- ...
MoveTrackDown id ->
-- ...

ModifyTrack id trackRowAction ->
let
updateTrack ( trackId, trackModel ) =
if trackId == id then
( trackId, TrackRow.update trackRowAction trackModel )
else
( trackId, trackModel )
in
( maybeAddPristine { model | tracks = List.map updateTrack model.tracks }
, Effects.none
)

0.17 implementation of update function in frontend/src/AlbumDetail.elm

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
-- ...

RemoveTrack id -> (1)
( { model \| tracks = List.filter (\( rowId, _ ) -> rowId /= id) model.tracks
}
, Cmd.none
)

MoveTrackUp id ->
-- ...

MoveTrackDown id ->
-- ...

ModifyTrack id trackRowMsg ->
case (modifyTrack id trackRowMsg model) of (2)
Just ( updModel, Nothing ) -> (3)
( model, Cmd.none )

Just ( updModel, Just dispatchMsg ) -> (4)
handleDispatch id dispatchMsg updModel

_ ->
( model, Cmd.none ) (5)

modifyTrack : TrackRowId -> TrackRow.Msg -> Model -> Maybe ( Model, Maybe TrackRow.DispatchMsg )
modifyTrack id msg model = (6)
ListX.find (\( trackId, _ ) -> id == trackId) model.tracks
\|> Maybe.map (\( _, trackModel ) -> TrackRow.update msg trackModel)
\|> Maybe.map
(\( updTrack, dispatchMsg ) ->
( maybeAddPristine
{ model
\| tracks =
ListX.replaceIf (\( i, _ ) -> i == id)
( id, updTrack )
model.tracks
}
, dispatchMsg
)
)

handleDispatch : TrackRowId -> TrackRow.DispatchMsg -> Model -> ( Model, Cmd Msg )
handleDispatch id msg model = (7)
case msg of
TrackRow.MoveDown ->
update (MoveTrackDown id) model

TrackRow.MoveUp ->
update (MoveTrackUp id) model

TrackRow.Remove ->
update (RemoveTrack id) model

1
The parent, ie AlbumDetail, logic for deleting on of it’s track rows

2
We delegate updating the track row and consequently the AlbumDetail model to a helper function.
We pattern match on the result from that function.

3
If it was a "normal" update with no dispatch message returned we simply return the updated model and a no op Cmd

4
If the update of the track row got a dispatch message in return from TrackRow.update we delegate the handling of the
dispatch message to another helper function.

5
Since we are dealing with Maybe values we have to handle this case, but it really shouldn’t ever happen ! (famous last words)

6
This might look a bit scary, but in summary it; locates the correct track row, performs the update of that row by delegating to TrackRow update,
updates the track row in the model with the updated track row and finally returns a tuple of the updated model and the dispatch message (which is Maybe you remember)

7
Here we simply pattern match on the dispatch message and invokes the update function with the appropriate corresponding Msg

The pattern we used here is just one of many possible ways of solving this problem. Maybe someday a common preferred pattern will emerge,
but the bottom line is that it will most likely be some variation of return values from update functions and/or input params to the view function in the parent/child communucation.
The days of "magic" juggling with mailboxes are gone. Simple input/output FTW !
Oh, and finally, for this particular case I think there might be a good case for arguing that perhaps remove/moveup/movedown doesn’t really belong in TrackRow at all, it might
actually make more sence to use a decorator-kind of approach instead.

Some flavors of using "global" or dummy effects (using say dummy tasks) for communicating between components have briefly surfaced. Pls think really carefully
before adopting such an approach. Have a chat with the nice and very knowledgable people in the community to discuss
if there isn’t a better solution for your problem !

Wiring it all together in frontend/src/Main.elm

Table 14. main

0.17
0.16

main : Program Never
main =
Navigation.program (1)
(Navigation.makeParser Routes.decode)
{ init = init
, view = view
, update = update
, urlUpdate = urlUpdate (2)
, subscriptions = \_ -> Sub.none (3)
}

1
Rather that start-app we are using the program function from Navigation. The first
param is a function to creates a parser- So bootstrap it with our Routes.decode function.
The second param is a config record similar to the one in start-app but not quite

2
Hey what’s this fellow, it seems we need to provide a function to handle URL updates in our application !

3
We don’t have any subscriptions in our app, so we can just return Sub.none for that function.

app : StartApp.App Model
app =
StartApp.start
{ init = init initialPath
, update = update
, view = view
, inputs = [ actions ] (1)
}

main : Signal Html
main =
app.html

port tasks : Signal (Task.Task Never ()) (2)
port tasks =
app.tasks

port initialPath : String (3)

1
Inputs was sort of like subscriptions. We needed that in our 0.16 because of elm-transit-router which used elm-history which again provided a signal for url changes.
All of that is gone and handled by navigation, but slightly differently.

2
Just a thing you had to define if you had effects in your App in 0.16. We’re happy it’s gone !

3
We had to provide the initialPath (url) through a port in 0.16

Table 15. Model and init stuff

0.17
0.16

type alias Model =
{ route : Routes.Route
, homeModel : Home.Model
, artistListingModel : ArtistListing.Model
, artistDetailModel : ArtistDetail.Model
, albumDetailModel : AlbumDetail.Model
}

initialModel : Model
initialModel =
{ route = Home
, homeModel = Home.init
, artistListingModel = ArtistListing.init
, artistDetailModel = ArtistDetail.init
, albumDetailModel = AlbumDetail.init
}

init : Result String Route -> ( Model, Cmd Msg ) (1)
init result =
urlUpdate result initialModel

1
init is called for us by Navigation.program using our provided parser so
we get a result from the parsing of the initial url. We pass that on to the yet to be described
urlUpdate function along with our initial model.

type alias Model =
WithRoute
Routes.Route
{ homeModel : Home.Model
, artistListingModel : ArtistListing.Model
, artistDetailModel : ArtistDetail.Model
, albumDetailModel : AlbumDetail.Model
}

initialModel : Model
initialModel =
{ transitRouter = TransitRouter.empty Routes.EmptyRoute
, homeModel = Home.init
, artistListingModel = ArtistListing.init
, artistDetailModel = ArtistDetail.init
, albumDetailModel = AlbumDetail.init
}

init : String -> ( Model, Effects Action )
init path =
let
usePath = if path == "/index.html" then "/" else path
in
TransitRouter.init routerConfig usePath initialModel

I don’t think it’s much point in describing the other slight differences, since they mostly pertain to
details about elm-transit-router.

Url updates / Mounting routes

mounting routes in 0.16

mountRoute : Route -> Route -> Model -> ( Model, Effects Action )
mountRoute prevRoute route model =
case route of
Home ->
( model, Effects.none )

ArtistListingPage ->
( model, Effects.map ArtistListingAction (ServerApi.getArtists ArtistListing.HandleArtistsRetrieved) )

ArtistDetailPage artistId ->
( model
, Effects.map ArtistDetailAction (ServerApi.getArtist artistId ArtistDetail.ShowArtist) )

NewArtistPage ->
( { model | artistDetailModel = ArtistDetail.init }, Effects.none )

-- etc ..

EmptyRoute -> (1)
( model, Effects.none )

1
This is how we handled route parse failures in our 0.16 implementation btw.

urlUpdate in 0.17

urlUpdate : Result String Route -> Model -> ( Model, Cmd Msg )
urlUpdate result model =
case result of
Err _ -> (1)
model ! [ Navigation.modifyUrl (Routes.encode model.route) ]

Ok (ArtistListingPage as route) -> (2)
{ model | route = route }
! [ Cmd.map ArtistListingMsg ArtistListing.mountCmd ]

-- rest left out for brevity

Ok ((NewArtistAlbumPage artistId) as route) -> (3)
{ model
| route = route
, albumDetailModel = AlbumDetail.initForArtist artistId
}
! [ Cmd.map AlbumDetailMsg AlbumDetail.mountNewAlbumCmd ]

Ok route -> (4)
{ model | route = route } ! []

1
If url parsing for a new url fails we just change the url back to url for the current route(/page)
It might be appropriate to show an error of some sort error.

2
When the we change url to the artist listing page we wish to initiate the http request for retrieving
artists from our backend. That’s where ArtistListing.mountCmd comes into the picture.

3
In addition to providing an effect, we need to ensure that the albumDetailModel starts with a clean slate
when the page for adding a new album is displayed. It might have been a good idea to separate this out to it’s own component to avoid quite a bit of coniditional logic.

4
For any other url changes we just update the route field in our model

What’s up with the ! [] thing ?

! is a shorthand infix function with the following signature (!) : model → List (Cmd msg) → (model, Cmd msg)

model ! [someCmd, someOtherCmd] == (model, Sub.batch [someCmd, SomeOtherCmd])

Just a little more on the main update function, related to navigation

0.17
0.16

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of

-- other actions left out

Navigate url ->
model ! [ Navigation.newUrl url ]

The navigate message triggers a call to the Navigation.newUrl function. That will step to a new url
and update the browser history. You’ll see in the next chapter were we trigger this message.

update : Action -> Model -> ( Model, Effects Action )
update action model =
case action of

-- other actions left out

RouterAction routeAction ->
TransitRouter.update routerConfig routeAction model

This is a elm-transit-router specific handler that takes care of starting and stopping animation transitions
+ updating the route field of our model

View

0.17
0.16

view : Model -> Html Msg
view model =
div
[ class "container-fluid"
, Routes.catchNavigationClicks Navigate (1)
]
[ menu model
, div [ class "content" ]
[ contentView model ] (2)
]

1
Here our catch all navigation related clicks helper function comes into play. So for any navigation related clicks, we return a Navigate msg with a payload of the url to navigate to.
This is will be handled in our top level update function as outlined in the previous chapter.
I’m not sold on it being a good solution, but it works !

2
we have already shown how the contentView function pattern matches on the route field of our model to render the appropriate page view

view : Signal.Address Action -> Model -> Html
view address model =
div
[ class "container-fluid" ]
[ menu address model
, div
[ class "content"
, style (TransitStyle.fadeSlideLeft (1)
100
(getTransition model))
]
[ contentView address model ]
]

1
This is particulars related to animations performed when making page transtions from elm-transit-*
That part got lost in our upgrade adventure, but should be possible to plug back in in the future should we want to.

Summary

Most of the changes went really smoothly and quickly. I did have to spend a little bit of time to get familiar with the new navigation and url-parser package, but they are pretty intuitive.
I wouldn’t be lying if I said I spent much more time on writing this blog post than doing the upgrade.
I also did quite a few changes to the implementation of details I haven’t shown you, just because I’ve become more confident with Elm than I was when writing the previous episodes.

It was quite a bit of changes in terms of LOC’s and I have to be honest and tell you it’t didn’t work once everything compiled. But you can hardly blame Elm for that,
it was all my bad. I hadn’t tested the route parsing properly and ended up implementing a loop. Kind of like a redirect loop, but all in js and out of reach for the browser.
Firing up the inline repl in Light Table and interactively testing the parser quickly showed me the errors of my ways.

All in all I have to say the upgrade was a really fun and enjoyable ride. I can definately say that
0.17 made the App turn out much nicer.

What’s next ?
Hard to say for sure, but my current thinking is to start looking at auth using JWT web tokens.
Time will tell if that’s what it’ll be.

Appendix

Unfortunately the 0.17 release left elm-reactor a bit behind in terms of what it supports.
From my past experience with ClojureScript, I have gotten used to the feeback loop you get by using the wonderful figwheel.
elm-reactor unfortunately doesn’t come close to that currently, so I had to turn to JS land for alternatives. After some evalutation and trials I ended up using
elm-hot-loader. It has worked out really nicely even though I ended up pulling down a fair chunk of the npm package repo.

I’m sure elm-reactor will be back with a vengeance in the not so distant future, packing some really cool and unique features.

Posted by LambdaCat on Tue, 05/10/2016 - 22:03

Today the new version of Elm, Elm 0.17 has launched, 6 months after 0.16.

Much has changed, but if you were using The Elm Architecture with StartApp (as it has been recommended for some time) you'll find that migrating won't be troublesome.

If, like me, you were using

Posted by LambdaCat on Fri, 04/22/2016 - 13:44

So on the 22nd of April I'm speaking at Progscon 2016, about Elm and Functional Reactive Programming.

I'm going to add more later, but here are slides and refs.

Slides

Elm: Finding the Functional in Reactive Programming

References

Elm Docs

Complete Guide
The Elm Architecture
Elm’s Time Traveling

Articles

Posted by LambdaCat on Tue, 04/19/2016 - 20:51

I've been developing a slightly bigger codebase than maybe average with Elm for a while, and I banged my head against some limits StartApp has. But an additional pattern has surfaced which helps a lot, even though it's not officially approved by Evan at the moment.

I'm going to show

Posted by Rundis on Thu, 04/07/2016 - 01:00

If you have worked with JavaScript (or quite a few other languages that embrace null) I bet you have had one or two errors that can be
traced back to an unexpected null reference. Some of them are obvious, but others are really tricky to
track down. I’m sure most of you are well aware that quite a few other languages banishes null and introduces a Maybe or Option type to handle nothingness.
Elm is one of those languages. Before I started looking at Elm I hadn’t really worked with Maybe types. In this blogpost
I thought I’d share a little more insight on how to work with them in Elm. I’ll also briefly cover how they might be (or not) used in JavaScript for reference.

Elm Maybe

Elm is a statically typed language which compiles down to JavaScript. Types is a core ingredient of Elm, that’s not the case with JavaScript obviously.

type Maybe a = Just a | Nothing

The Maybe type in Elm looks deceivingly simple. And actually it is.
The type is parameterized and the a is a placeholder for a concrete type in your program.
So a here means any type (Int, String, Float etc). A Maybe can have one of two values; either Just some value of type a or it is Nothing.
Where does Just and Nothing come from ? Are they defined somewhere else ? They are part of the type definition, think of them as tags. The name of these "tags"
must start with an upper case letter in Elm.

x = Just 0.0 -- Just 0.0 : Maybe.Maybe Float (1)

y = Nothing -- Nothing : Maybe.Maybe a (2)

1
The variable x Maybe with the tag Just and the Float value 0.0 (Maybe lives in a namespace or rather module in Elm called Maybe, that’s why the actual type definitions states Maybe.Maybe)

2
The variable y becomes a Maybe with the tag Nothing. Nothing has no value, and hence no value type associated. Nothing is Nothing, but it’s still a Maybe though :-)

Quick detour - Type annotations

Elm is a statically typed language, everything is represented through types. So before
we carry on I’d like to briefly cover the concept of type annotations.

Since JavaScript doesn’t have types, I’ll use Java as a comparable example

Sample Java functions

public int increment(int value) {
return value++;
}

public int add (int x, int y) {
return x + y;
}

Type annotated equivalents in Elm

increment : Int -> Int (1)
increment value =
value = value + 1

add : Int -> Int -> Int (2)
add x y =
x + y

1
The type annotation for increment tells us it is a function which takes an argument of type Int and returns an Int

2
add takes two arguments of type Int and returns a an Int. So think of the last one as return type.

Type annotations in Elm are optional, because the compiler is able to infer the types statically.
Most people tend to use type annotations because they provide very useful documentation.
When working with Elm it’s really something you quickly have to learn, because most documentation will use them
and the Elm compiler will most certainly expose you to them.

Getting the actual values from a Maybe

Ok so I have this maybe thing which can be a Just some value or Nothing. But how do I get
hold of the value so I can work with it ?

Pattern matching

myList : List String (1)
myList = ["First", "Second"] (2)

-- List.head : List a -> Maybe.Maybe a (3)

case List.head myList of (4)
Nothing -> (5)
"So you gave me an empty list!"

Just val -> (6)
val

-- returns "First"

1
Type annotation for myList. It is a List of String. It’s just a value, so that’s why there is no arrows in the type annotation

2
We are using a list literal to define our list. Each list item must be separated by a comma. It’s also worth noting, that every item in the list must be of the same type. You can’t mix Strings with Ints etc. The Elm compiler will yell at you if you try

3
I’ve added the type annotation for the List.head function. Given a List of values with type a it will return a Maybe of type a. List.head returns the first item of a List. The reason it returns a Maybe is because the List might be empty.

4
You can think of case as a switch statement on stereoids. Since List.head return a Maybe we have to possible case’s we need to handle

5
In this instance we can see from the code this case will never happen, we know myList contains items. The Elm compiler is really smart, but not that smart so it doesn’t know the list is empty.

6
This case unwraps the value in our Just so that we can use it. We just return the value, which would be "First".
The value is unwrapped using something called pattern matching. In JavaScript terms you might think of it as destructuring

The Maybe module
The Maybe type is defined in a module called Maybe. In addition to the Maybe type it also includes a collection
of handy functions that makes it handy to work with Maybe types in various scenarios.

myList = ["First", "Second", "Third"]

first = List.head myList
second = List.head (List.drop 1 myList)
tail = List.tail myList -- Just ["Second","Third"] : Maybe (List String)

-- Maybe.withDefault : a -> Maybe a -> a (1)
Maybe.withDefault "No val" first -- -> "First" (2)
Maybe.withDefault "No val" (List.head []) -- -> "No val"

-- Maybe.map : (a -> b) -> Maybe a -> Maybe b (3)
Maybe.map String.toUpper first -- -> Just "FIRST" (4)
Maybe.map String.toUpper Nothing -- -> Nothing

-- Maybe.map2 (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c (5)
Maybe.map2 (\a b -> a ++ ", " b) first second -- -> Just "First, Second" (6)
Maybe.map2 (\a b -> a ++ ", " b) first Nothing -- -> Nothing
Maybe.map2 (++) first second -- -> Just "First, Second" (7)

-- Maybe.andThen Maybe.Maybe a -> (a -> Maybe b) -> Maybe b (8)
Maybe.andThen tail List.head -- -> Just "Second" (9)
tail `Maybe.andThen` List.head -- -> Just "Second" (10)

tail
`Maybe.andThen` List.head
`Maybe.andThen` (\s -> Just (String.toUpper s)) -- -> Just "SECOND" (11)

Just []
`Maybe.andThen` List.head
`Maybe.andThen` (\s -> Just (String.toUpper s)) -- -> Nothing (12)

1
Maybe.withDefault takes a default value of type a a Maybe of type a. It returns the value of the maybe if it has a value (tagged Just) otherwise it returns the provided default value

2
In the first example first is Just "First" so it unwraps the value and returns that. In the second example there is no value so it returns the provided default

3
Maybe.map takes a function which has the signature (a → b), that means a function that takes any value of type a and return a value of type b (which can be the same type or a completely different type). The second argument is a Maybe (of type a). The return value is a Maybe of type b. So Maybe.map unwraps the second argument, applies the provided function and wraps the result of that in a Maybe which in turn is returned.

4
String.toUpper takes a String (a if you like) and returns a String (b if you like). String.toUpper doesn’t understand Maybe values, so to use it on a Maybe value we can use Maybe.map

5
Maybe.map2 is similar to Maybe.map but the function in the first argument takes two in parameters. In addition to the function param we provide two Maybe values. These two doesn’t need to be of the same type, but happens to be so in our example. There is also map3, map4 etc up to map8

6
If any or both of the two Maybe params are Nothing the result will be Nothing.

7
In the example above we used an anonymous function (lambda). However ++ is actually a function that takes two arguments so we can use that as the function argument

8
Maybe.andThen resembles Maybe.map but there are two vital differences. The function argument comes as the second param (we’ll come back to why), secondly the function in the function argument must return a Maybe rather than a plain value.

9
The first argument tail is a Maybe, the second argument is List.head which is a function that takes a list as an argument and returns a Maybe, so that conforms to the function params signature required by Maybe.andThen

10
In this version we use the infix version of andThen (marked by backticks before and after). This is the reason the function argument comes second, so you typically use Maybe.andThen when you you need to work with maybes in a pipeline sort of fashion.

11
This is an example of piping values when dealing with Maybe values. We start with the tail of our list and then we pick out the head of that list and then we convert the value of that to uppercase

12
You can almost think of andThen as a callback. If any step of the chain returns Nothing, the chain is terminated and Nothing is returned

Don’t like the way Maybe sound, how about rolling your own ?

type Perhaps a = Absolutely a | NotSoMuch

Of course interop with others will be an issue and Maybe has some advantages being part of the core library. But still
if you really really want to…​

JavaScript null/undefined

function headOfList(lst) {
if (lst && lst.length > 0) {
return lst[0];
} else {
// hm... not sure. let's try null
return null;
}
}

function tailOfList(lst) {
if (lst && lst.length > 1) then
return lst.slice(0);
} else {
// hm... not sure. let's try null
return null;
}
}

var myList = ["First", "Second", "Third"];
var first = headOfList(myList); // "First"
var second = headOfList(tailOfLIst(myList)) // "Second"
var tail = tailOfList(lst); // ["First", "Second"]

first // "First"

headOfList([]) // null (1)

first.toUpperCase() // "FIRST"
headOfList([]).toUpperCase() // Type Error: Cannot read property 'toUpperCase' of null (2)

first + ", " + second // "First, Second"
first + ", " + null // "First, null" (3)

headOfList(tail).toUpperCase() // "SECOND"
headOfList([]).toUpperCase() // Type Error: Cannot read property 'toUpperCase' of null (4)

1
An empty list obviously doesn’t have a first item.

2
If this was in a function you might guard against this. But what would you return ? Would you throw a exception ?

3
Doesn’t look to cool, so you would have to make sure you guarded against this case. Let’s hope you tested that code path, otherwise it’s lurking there waiting to happen !

4
Same as 2

Okay so most of this cases are pretty silly, we would have to come up with something more real life
with functions calling functions calling functions etc. The bottom line is that you have to deal with it,
but it’s up to you all the time to make sure nulls or undefined doesn’t sneak in. In most cases there are simple non verbose
solutions to deal with them, but it’s also quite easy to miss handling them. If you do it can sometimes be quite a challenge tracking down
the root cause.

It’s undoubtably a little more ceremony in Elm, but in return you will not ever get nullpointer exceptions.

Introducing Maybe in JavaScript

If you are from a JavaScript background the blogpost Monads in JavaScript gives you a little hint on how you could implement Maybe in JavaScript.

Let’s borrow some code from there and see how some of the examples above might end up looking

Defining Just and Nothing

function Just(value) {
this.value = value;
}

Just.prototype.bind = function(transform) {
return transform(this.value);
};

Just.prototype.map = function(transform) {
return new Just(transform(this.value));
};

Just.prototype.toString = function() {
return 'Just(' + this.value + ')';
};

var Nothing = {
bind: function() {
return this;
},
map: function() {
return this;
},
toString: function() {
return 'Nothing';
}
};

A few helper functions for dealing with JavaScript arrays

function listHead(lst) {
return lst && list.length > 0 ? new Just(lst[0]) : Nothing;
}

function listTail() {
return lst && list.length > 1 ? new Just(lst.slice[1]) : Nothing;
}

Elm examples in JavaScript with Maybe’ish support

var myList = ["First", "Second", "Third"];
var first = listHead(myList);
var second = listTail(myList).bind(t => listHead(t));
var tail = listTail(myList);

// Similar to Maybe.map in Elm
first.map(a => a.toUpperCase()) // Just {value: "FIRST"} (1)
Nothing.map(a => a.toUpperCase()) // Nothing (object) (2)

// Similar to Maybe.map2 in Elm
first.bind(a => second.map( b => a + ", " + b)) // Just { value: 'First, Second' } (3)
first.bind(a => Nothing.map( b => a + ", " + b)) // Nothing (object)

// Similar to Maybe.andThen in Elm
tail.bind(a => listHead(a)).bind(b => new Just(b.toUpperCase())) // Just { value: 'SECOND' } (4)
new Just([]).bind(a => listHead(a)).bind(b => new Just(b.toUpperCase())) // Nothing (object) (5)

1
first is a Just object. Since it has a value the arrow function is run as expected

2
When the value is Nothing (a Nothing object) toUpperCase is never run and the Nothing object is returned

3
In the arrow function of bind for first we ignore the unwrapped value and call map on second with a new arrow function which now has both the unwrapped value of both a and b. We concatenate the values and the map function ensures the result is wrapped up in a Just object
If you remember the elm case for map2, that was a separate function. Here map is just a convenience to wrap up the innermost value in a Just.

4
tail is a Just object with the value ["First", "Second"] in the first level arrow function we pick out the head which returns a Just object with the value "Second". In the innermost arrow level function we do upperCase on the value and wrap in it a Just which is the end result.

5
We are starting with Just with a value of an empty array. In the first level arrow function we try to pick out the head of the list. Since that will return a Nothing object, Nothing passes straight through the second level arrow function, never executing the toUpperCase call.

So as you can see it is possible to introduce the notion of Maybe in JavaScript. There are several libraries out there to choose from
I haven’t really tried any of them. Regardless the issue you’ll be facing is that the other libraries you are using probably won’t be using your representation of Maybe if at all.
But hey, maybe it’s better with something than nothing. Or whatever.

Wrapping up

There is clearly a slight cost with explicitly handling nothingness everywhere. In Elm you basically don’t even have a choice. The type system
and the compiler will force you into being explcit about cases when you don’t have a value. You can achieve the same as with null but
you always have to handle them. In your entire program. The most obvious benefit you get, is that you simply will not get null reference related errors in Elm. When calling any function
that accepts Maybe values as input params or return Maybe values you will be made well aware of that. The compiler will let you know, but typically you would also see type annotations stating this fact too.
This explicitness is actually quite liberating once you get used to it.

In JavaScript you can try to be more explicit with nulls. You can even reduce the chances of null pointers ever happening by
introducing a Maybe/Option like concept. Of course you wouldn’t introduce the possibility of null pointers in your code. However there’s a pretty big chance
some bozo,responsible for one of the 59 libs you somehow ended up with from npm, have though.

There are plenty of bigger challenges than null pointer exceptions out there, but if you could avoid them altogether,
surely that must a be of some benefit. I’ll round off with the obligatory quote from Tony Hoare as you do when one pays tribute to our belowed null.

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

— Tony Hoare

Posted by Rundis on Mon, 03/28/2016 - 01:00

Maybe you are a package author for Elm packages you wish to publish to http://package.elm-lang.org/
. Or maybe you are thinking about authoring a package. Before you publish something to the package repo
you have to write documentation for your package. Wouldn’t it be sweet if you could preview the
generated documentation from the comfort of your editor ?

The good news is that with the latest (0.3.6) edition of the elm-light plugin
you can !

Demo

Link to demo

Feature highlights

  • Preview how the docs will look for each individual module
  • The preview is updated whenever you save your (exposed) Elm module file
  • Layout pretty close to how it will look on http://package.elm-lang.org/ once published
  • Fast (at least on my machine !)
  • Minor detail, but the entire preview UI is also implemented in Elm (ultimate dogfooding). It’s
    basically a modified and simplified implementation of the package preview code for http://package.elm-lang.org/

Resources