Elmchemy — Write type-safe Elixir code with Elm’s syntax — part 1 — Introduction

Published Jul 20, 2017Last updated Jan 16, 2018
Elmchemy — Write type-safe Elixir code with Elm’s syntax — part 1 — Introduction

We all love Elixir. It’s expressive, it’s extremely readable and - first and foremost - It runs on BEAM — an incredible virtual machine that turns concurrency into something as natural and expected as NullPointerExceptions in Java 7.

But as every language does, it also has its flaws. Some are inherent, some are just religious choices that had to be made one way or another; and as the user (or rather fan) base grows, so does the demand to express your own preferences. Changes like piping to the last argument instead of the first can be introduced with simple macros. Some people craving for more advanced ideologies create entire toolsets extending the language (like Railway Oriented Programming or Saša Jurić’s Exactor). Some others commit to entire frameworks that start to look like DSLs instead (Witchcraft).
But even smartest macro can’t solve everything without surpassing the biggest meta-programmer’s limitation: syntax. So that’s what we changed.

Arguably one of the loudest religion choices is typing. Private jokes like “Strong typing is for weak minds” and “If you shoot yourself in the foot, it’s easier to solve the problem by being careful not to aim the gun at your foot than it is to make guns that don’t point down” roam around the community. Whether types are hot or not, is out of this article’s scope. 
I like strong types. And I like Elixir. 
And that’s why Elmchemy was made.

What does strong typing give us anyway?

Generally strong typing pays attention so you don’t have to. 
You put a typo in function params?
 Compiler will tell
Your arguments are in wrong order.
 Compiler will tell
You wrongly treat a list of {:ok, value} tuples as if they were just value’s.
 Compiler will tell.

So whether your application works on complex nested structures, you like extra safety, or you just suffer from short attention span, static typing probably will serve you well.

Elmchemy to the rescue!

With all of those values in mind, we came out with Elmchemy:

wende/elmchemy
_elmchemy - Write Elixir code using Elm-inspired syntax (elm-make compatible)_github.com

Without further and unnecessary descriptions. Elmchemy is entirely about turning this:

Into this:

Does it work? Check by yourself.

“But wait. I just typed> a : String
a = 1> And it totally went through. Where is the entire type safety in that? You suck!”

Worry not. The type safety’s there. Just not in the browser, but living safely in the depths of the entire toolkit to integrate Elmchemy with your existing Elixir project.

And to prove and learn the basics of it, below we’ll write a simple example program from scratch.


We don’t have any project so we’ll start a new one:

$ mix new article_example_elmchemy$ cd article_example_elmchemy

Now we also need to install Elmchemy and initialize it in our project
So let’s do that and try out how our type safety is doing.

$ npm install -g elmchemy$ elmchemy init

Terminal responds to us with:

Elmchemy initialised. Make sure to add:
compilers: [:elmchemy, :yecc, :leex, :erlang, :elixir, :app], elixirc_paths: ["lib", "elm-deps"], elmchemy_path: "elm",
to your mix.exs fileThen run mix test to check if everything went fine

So I open an editor of my choice

$ atom mix.exs

And add the missing lines

Great! We’re good to go. Let’s type mix test to make sure that we’re all set.

We should see a ton of logs and warnings. But don’t worry — as long as the tests are passing everything’s fine!

Check. So now let’s open elm/Hello.elm and implement our first example.

*If you don’t have any Elm language plugin/extension/layer in your editor, you should probably install one now*

We’ll implement a functional programming ‘hello world’ — a sum of a list!
Since most of the editors organize files based on git repository files - as a minimum setup let’s first make an initial commit.

git init && git add . && git commit -am "init"

And let’s go!
 
Ok. So as we are grown up developers, we’re going to start with a unit test suite for our future code.
Let’s write a simple test case making sure that our sum of integers is what it’s meant to be.

*If you’re not yet familiar with ExUnit tests syntax you should probably be reading this article instead*

In your project, open test/elmchemy_test.exs and paste this code

Run mix test once again and we should see this result:

Great!

Head back to elm/Hello.elm and let’s implement the sum function.

We’re gonna start with a type signature. Our sum function obviously takes a list and returns a sum. Presumably an integer. So let’s type it!


The type signature for our new sum function

Ok. Now it’s the time for our implementation.

Classically we’ll write a sum as a recursion, where we take a head of a list and add it to the application of the same function on the tail , with an exception of returning just 0 if the list is empty.
Which should look like this


Save our file and…. wait a second. There’s an error.

Oh… That’s right! Since we’re no longer in a world of dynamic typing, we can’t just add any two things together. Addition is an operator reserved for numbers only.
That means our type signature is incorrect.
Let’s fix it by changing to sum : List Int -> Int

Perfect!
Let’s run our test case again and see how it’s doing

Alright! We’ve got our first functional program. Now let’s add some bells and whistles to it. We’ll start by removing the test we just wrote. We don’t need an entire test case just for a simple sum function. Let’s make it a doctest!

Remove the test case and write a beautiful doc for our newly born function.
Same as in Elm we write a docstring using {-| -} comment block. So let’s do exactly that

That should be just right. Let’s run our mix test again.

If we removed our previous test case, we should now have 
7 tests 0 failures report from our test suite; each one of our doctest lines being a separate test case.

But what did we write anyway?

Although the Elmchemy code is sufficient on it’s own and there is no need to look at the generated output, it’s good to make a sanity check, so we know what does the written code do to the rest of our codebase.

To do that, we can look at generated Main.ex file inside our output lib/ folder.

This is the part relevant to what we just wrote.

Let’s break it down.

At #23 We start with a @doc string that works as a documentation for our function. 
Then between #26–36 we have three generated examples in Elixir doctest format.
At Line #41 We can see the typespec signature for a curried version of our function — this is how our function will be called from inside Elmchemy.
Line #42 Is a regular typespec, generated only for function usage out of Elmchemy — directly from Elixir code
Line #43 is a bit of Elmchemy magic that makes our function accessible in curried form
Line #44–49 is exactly what we’d do writing the function by hand, with a tiny exception of a mysterious dot in sum.(rest) which for now will remain unexplained. Generally it’s because in Elmchemy everything is curried.

That’s all for part one.
In the next part we’ll learn how to create an entire library, using 
modules from elmchemy-core, defining your own types, type aliases and operators.

GO TO PART TWO

Discover and read more posts from Krzysztof Wende
get started