Functional programming with Elixir
Magic Potion

© Lead Image © Csaba Arva, 123RF.com
Developers will appreciate Elixir's ability to build distributed, fault-tolerant, and scalable applications.
Elixir 1.0 [1] offers easy entry into the world of functional programming by relying on the Erlang [2] virtual machine. An Elixir program can invoke any Erlang function with no run-time cost. In this article, I demonstrate Elixir's capabilities by rolling out the distributed server system shown in Figure 1. The system runs a proxy on the first server node and forwards incoming HTTP requests to one of two server nodes on the local network to boost performance. Both nodes store the content redundantly and deliver identical documents on request that are delivered as responses to the clients via the proxy.

Friendly Parasite
Listing 1 shows the installation of the current version of Elixir (version 1.0.4-1) on Ubuntu 14.04. Line 1 uses wget
to pick up a Debian package that points to an external package repository with the current versions of Elixir and Erlang. The dpkg
package manager bundles the list in line 2 to the correct location on the filesystem; the next line updates and parses the list. Finally, Elixir and the erlang-dev
packages are installed on the computer.
Listing 1
Installing Elixir
The iex
command launches an interactive session in the shell after completing the install. The expression
:crypto.md5("Using crypto from Erlang OTP")
tests whether Elixir is compatible with Erlang by calling the md5()
function from Erlang's Crypto module. In the shell, iex
should display the string returned by md5()
as a byte sequence enclosed in angled brackets (Figure 2).

In addition to byte sequences, Elixir supports tuples, lists, and structs for storing structured data. The list
[{:app, :httpd}, {:version, "0.0.1"}]
stores the {:app, :httpd}
tuple in its header; the tuple in turn contains two literals: :app
and :httpd
. Literals that are introduced by a :
are known in Elixir-speak as atoms. The language makes liberal use of them.
To evaluate data structures, Elixir comes with patterns, emulating the style of Haskell [3]. An example of a pattern can be seen to the left of the equals sign in the following expression
[{a, b}|_] = [my: :house, your: :house]
Before Elixir compares it with the list on the right, it first converts to the standard form [{:my, :house}, {:your :house}]
.
On comparing the pattern, the tuple in the list header on the left side matches the tuple in the list header on the right side. Both tuples store two elements. The variables a
and :my
and b
and :house
are tangible after the compare. The _
operator to the right of the pipe symbol in the pattern matches any expression; in this example, :your :house
. Figure 2 shows the values from a
and b
again after pattern matching.
Everything Under Control
The mix
build tool helps implement Elixir projects. When started at the command line, it compiles, launches, and tests projects. Just like iex
, mix
ends up on your computer when you install Elixir. The
mix new httpd
command creates the application skeleton for the planned web server (Listing 2). The mix.exs
file stores the project configuration (Listing 3); line 1 uses the defmodule
keyword to define an Elixir module named Httpd.Mixfile
; the code then continues with a do
/end
block to line 15.
Listing 2
Application Skeleton
Listing 3
httpd/mix.exs (Project Configuration)
Line 2 calls use
to integrate the Mix.Project
macro. Public functions such as project()
are introduced by the def
keyword, whereas defp
is used for private functions and deps()
. The keywords are followed by the function name and an optional list of parameters. The do
/end
block that follows defines the return values of the functions.
The call to the function project()
(lines 4-9) returns the project's core data in the form of a list, and deps()
(line 11) lists the dependencies of the project. They include the Cowboy [4] web server framework (version 1.0.0 or newer), which is written in Erlang, and Plug [5] middleware (version 0.13 or newer).
Private functions can only be called within the module. If you type Http.Mixfile.deps()
in the interactive iex
shell, you will see an (UndefinedFunctionError
) message.
Advanced Code
Listing 4 shows the code for lib/httpd.ex
, in which the Httpd module responds to HTTP requests, invoking the Elixir Plug module to do so. The module processes HTTP requests in the pipeline in a fashion similar to the Node.js Connect middleware framework [6].
Listing 4
httpd/lib/httpd.ex (Httpd Module)
The Plug framework first fields a request object from a web server and passes it on to a number of filter functions, or plugs. The plugs evaluate the object, modify it, and delegate it to a downstream plug. Alternatively, the plugs tell the framework to terminate the pipeline by calling the send_resp()
function (lines 10 and 14). They use the function's call parameters to construct an HTTP response, which they then return to the web server (Figure 3).

Listing 4 first binds the Plug.Router
and Plug.Builder
macros. The plug()
function (lines 5-7) registers the plugs and keeps them in a FIFO (first in, first out) queue. As mentioned earlier, the program processes the queue as soon as a request object arrives.
The Static
plug in line 5 creates a URL that matches a location on the server's directory system. Because of the at:
statement, the URL http://127.0.0.3/info.html sends the /home/pa/info.html
file to the client. If no file matches the URL, the downstream plug picks up the HTTP request. The :match
and :dispatch
statements work hand in hand. Whereas :match
uses pattern matching to find suitable HTTP requests and forwards matches to :dispatch
, :dispatch
takes care of the HTTP response.
The code blocks in lines 9-11 and 13-15, do not contain any native Elixir code. Instead, they are code extensions created by the plug's inventor [7]. The plug router macro converts these code blocks into valid tree components when building the syntactical tree. Theoretically, you could implement the code block as an Elixir expression:
{method: "get", url: "/info", _} -> \ Usend_resp(conn, 200, inspect(conn))
Listing 4 takes a different approach, however. Lines 9-11 output a formatted version of the request object in the body of the HTTP response to the /info
URL thanks to the inspect()
function.
The function writes 200 as a response code to the response header. For any requests that have not received a response, lines 13-15 return the well-known 404 message to the client via the web server. Before starting the application, the user needs to change to the project directory then build the application by running Mix. The command first loads the source code of the required modules from Hex.pm [8], the package archive shared by Erlang and Elixir; then, the application is compiled into a bevy of BEAM files. The files end up in the project directory below the _build
folder. The iex
command again starts an interactive session:
cd httpd mix deps.get mix deps.compile sudo iex -S mix
The function call
Plug.Adapters.Cowboy.http Httpd, [], \ ip: {127, 0, 0, 3}, port: 80
starts an instance of the web server from the Cowboy framework. The server is then reachable via the IP address 127.0.0.3 and port 80; it loads the module from Listing 4, which then waits for HTTP requests. Figure 4 shows a formatted request object as a response to the request URL http://127.0.0.3/info in the Firefox browser view.

Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you've found an article to be beneficial.
News
-
Arch Linux 2023.12.01 Released with a Much-Improved Installer
If you've ever wanted to install Arch Linux, now is your time. With the latest release, the archinstall script vastly simplifies the process.
-
Zorin OS 17 Beta Available for Testing
The upcoming version of Zorin OS includes plenty of improvements to take your PC to a whole new level of user-friendliness.
-
Red Hat Migrates RHEL from Xorg to Wayland
If you've been wondering when Xorg will finally be a thing of the past, wonder no more, as Red Hat has made it clear.
-
PipeWire 1.0 Officially Released
PipeWire was created to take the place of the oft-troubled PulseAudio and has finally reached the 1.0 status as a major update with plenty of improvements and the usual bug fixes.
-
Rocky Linux 9.3 Available for Download
The latest version of the RHEL alternative is now available and brings back cloud and container images for ppc64le along with plenty of new features and fixes.
-
Ubuntu Budgie Shifts How to Tackle Wayland
Ubuntu Budgie has yet to make the switch to Wayland but with a change in approaches, they're finally on track to making it happen.
-
TUXEDO's New Ultraportable Linux Workstation Released
The TUXEDO Pulse 14 blends portability with power, thanks to the AMD Ryzen 7 7840HS CPU.
-
AlmaLinux Will No Longer Be "Just Another RHEL Clone"
With the release of AlmaLinux 9.3, the distribution will be built entirely from upstream sources.
-
elementary OS 8 Has a Big Surprise in Store
When elementary OS 8 finally arrives, it will not only be based on Ubuntu 24.04 but it will also default to Wayland for better performance and security.
-
OpenELA Releases Enterprise Linux Source Code
With Red Hat restricting the source for RHEL, it was only a matter of time before those who depended on that source struck out on their own.