Skip to content

Instantly share code, notes, and snippets.

@choonkeat
Last active October 5, 2020 10:26
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save choonkeat/0f37b528f6afd8887e5e245c3f3de756 to your computer and use it in GitHub Desktop.
Save choonkeat/0f37b528f6afd8887e5e245c3f3de756 to your computer and use it in GitHub Desktop.
  • Elm is not a frontend framework.
  • Elm is neither V in MVC, nor MV in MVC, nor even MVC itself.
  • You don't assemble libraries and configure options to make Elm do what you want.

Elm is a language. You write programs with it.

But instead of providing a regular main function to run, Elm wants you to write at least 2 parts to run your program: init and update. This is my pseudo code for your init and update plugs into Elm runtime:

let [globalState, cmd] = init(optionFlags)

const messageBus = new EventEmitter()

messageBus.on('msg', function (msg) {
  const [newState, newCmd] = update(msg, globalState)
  globalState = newState                              // NOTE: globalState changes every update
  execAndEmitMsg(newCmd, messageBus)
})

execAndEmitMsg(cmd, messageBus)

NOTE: if you are unfamiliar with EventEmitter, it is a "message bus" that provide emit and on listeners alternatively, you may prefer the Go example

Backend web devs are very familiar with writing programs in an event-driven manner: each incoming http request is handled by a stateless function, reading and writing a global database. Imagine doing the same, but not just to handle incoming http requests.

Elm is just saying, that's how we write all Elm programs.

In addition, Elm is saying it is best if init and update functions cannot perform any actual commands like open a file, or http get. Instead just return plain values to tell the runtime what to execute next:

cmd = { type: "Http.get", url: "http://roll.diceapi.com/json/d6", msg: "RollDice" }

In the first pseudo code on top, these cmd values are handed off to a runtime function execAndEmitMsg that performs the real actions:

function execAndEmitMsg (cmd, messageBus) {
  switch (cmd.type) {
    case 'Http.get':
      fetchText(cmd.url).then((data) => messageBus.emit('msg', [cmd.msg, data]))
      break
  }
}

Notice that messageBus.emit('msg', ...)? That's how the result is passed back through messageBus.on('msg', ...) and handled by your update

And just like that, round and round we go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment