Functional programming with Elixir
Magic Potion
![© Lead Image © Csaba Arva, 123RF.com © Lead Image © Csaba Arva, 123RF.com](/var/linux_magazin/storage/images/issues/2015/181/elixir-1.0/123rf_16501678_magic-potion_csabaarva_resized.png/659517-1-eng-US/123RF_16501678_Magic-potion_CsabaArva_resized.png_medium.png)
© 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.
![](/var/linux_magazin/storage/images/issues/2015/181/elixir-1.0/figure-1/659520-1-eng-US/Figure-1_large.png)
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.
![Learn More](https://www.linux-magazine.com/var/linux_magazin/storage/images/media/linux-magazine-eng-us/images/misc/learn-more/834592-1-eng-US/Learn-More_medium.png)
News
-
NVIDIA Released Driver for Upcoming NVIDIA 560 GPU for Linux
Not only has NVIDIA released the driver for its upcoming CPU series, it's the first release that defaults to using open-source GPU kernel modules.
-
OpenMandriva Lx 24.07 Released
If you’re into rolling release Linux distributions, OpenMandriva ROME has a new snapshot with a new kernel.
-
Kernel 6.10 Available for General Usage
Linus Torvalds has released the 6.10 kernel and it includes significant performance increases for Intel Core hybrid systems and more.
-
TUXEDO Computers Releases InfinityBook Pro 14 Gen9 Laptop
Sporting either AMD or Intel CPUs, the TUXEDO InfinityBook Pro 14 is an extremely compact, lightweight, sturdy powerhouse.
-
Google Extends Support for Linux Kernels Used for Android
Because the LTS Linux kernel releases are so important to Android, Google has decided to extend the support period beyond that offered by the kernel development team.
-
Linux Mint 22 Stable Delayed
If you're anxious about getting your hands on the stable release of Linux Mint 22, it looks as if you're going to have to wait a bit longer.
-
Nitrux 3.5.1 Available for Install
The latest version of the immutable, systemd-free distribution includes an updated kernel and NVIDIA driver.
-
Debian 12.6 Released with Plenty of Bug Fixes and Updates
The sixth update to Debian "Bookworm" is all about security mitigations and making adjustments for some "serious problems."
-
Canonical Offers 12-Year LTS for Open Source Docker Images
Canonical is expanding its LTS offering to reach beyond the DEB packages with a new distro-less Docker image.
-
Plasma Desktop 6.1 Released with Several Enhancements
If you're a fan of Plasma Desktop, you should be excited about this new point release.