341 lines
22 KiB
HTML
341 lines
22 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Markdown To HTML Transpiler Demo</title>
|
|
<link rel="stylesheet" href="./demo.css" />
|
|
</head>
|
|
|
|
<body>
|
|
<div class="journal-wrapper prose">
|
|
<p>Date: 2025/04/28 Desc: I have decided to begin the journey of learning functional programming. Here is my
|
|
experience.</p>
|
|
<h1>What is a Functional Programming Language: Featuring Elixir</h1>
|
|
<p><img src="https://hhargreaves.net/journal/elixir-logo.png" alt="Jet Brains Logo"
|
|
style="background-color: white; border-radius: 15px; padding: 10px; margin-inline: 10px; margin-block: 2.5%;"
|
|
width="300"></p>
|
|
<p><br></p>
|
|
<h6>Author: Hayden Hargreaves</h6>
|
|
<h6>Published: 05/21/2025</h6>
|
|
<h2>Background</h2>
|
|
<p>Many programmers tend to avoid <strong>functional programming</strong> due to its perceived complexity, myself
|
|
included. But is functional programming really that much more complex? My goal is to break my fear of functional
|
|
programming, <a href="https://en.wikipedia.org/wiki/Monad_(functional_programming" target="_blank">monads</a>), <a
|
|
href="https://en.wikipedia.org/wiki/Functor" target="_blank">functors</a>, and all those <em>scary</em> terms
|
|
frequently tossed around in the functional space.</p>
|
|
<p>How am I going to do this? Well, I am definitely not going to start with <a href="https://www.haskell.org"
|
|
target="_blank">Haskell</a>. For those who have never seen or heard of Haskell, this decision might be hard to
|
|
understand. I will not explain myself too much. But I will provide a code snippet from the Haskell docs and let
|
|
you decide if it a worthy language for someone who has never written a line of functional code in their life.</p>
|
|
<code>
|
|
haskell
|
|
<br>
|
|
primes = filterPrime [2..] where
|
|
<br>
|
|
filterPrime (p:xs) =
|
|
<br>
|
|
p : filterPrime [x | x <- xs, x `mod` p /=0] <br>
|
|
|
|
</code>
|
|
<p>Personally, the Haskell language is far too esoteric for my liking. Eventually, I would love to be able to, at
|
|
the very least, <strong>read</strong> Haskell code, but not yet. So this put me a spot to select from a large
|
|
selection of languages. I did not want to use a language like <strong>Python</strong> or
|
|
<strong>JavaScript</strong> which can be written to <em>seem</em> functional. No, I wanted to write a
|
|
<strong>real</strong> functional language. A common list of as follows:
|
|
</p>
|
|
<ul>
|
|
<li><a href="https://www.haskell.org" target="_blank">Haskell</a></li>
|
|
<li><a href="https://www.erlang.org" target="_blank">Erlang</a></li>
|
|
<li><a href="https://elixir-lang.org" target="_blank">Elixir</a></li>
|
|
<li><a href="https://www.scala-lang.org" target="_blank">Scala</a></li>
|
|
<li><a href="https://clojure.org" target="_blank">Clojure</a></li>
|
|
<li><a href="https://ocaml.org" target="_blank">OCaml</a></li>
|
|
<li><a href="https://lisp-lang.org" target="_blank">Common Lisp</a></li>
|
|
</ul>
|
|
<p>To avoid offending all of the "functional bros" I will not explain my thought process much. However, I will
|
|
mention that I tried to learn <strong>OCaml</strong> a years ago and could not enjoy it. Maybe that was because I
|
|
was not as advanced as I am today, or maybe I did not have the proper mindset. Regardless, that ruled out OCaml. I
|
|
have no experience in any of the other languages, so I did what most would do. I let Reddit decide! The <a
|
|
href="https://www.reddit.com/r/elixir/" target="_blank">Elixir</a> Reddit page was very informative as well as
|
|
providing me with a link to the <a href="https://survey.stackoverflow.co/2024/technology#top-paying-technologies"
|
|
target="_blank">2024 Stack Overflow Survey</a> which described Erlang and Elixir as the top two paying
|
|
languages. </p>
|
|
<p>With that out of the way, lets talk more about what functional programming is.</p>
|
|
<h2>What is Functional Programming</h2>
|
|
<p>At the most basic level, functional programming is defined as a <a
|
|
href="https://en.wikipedia.org/wiki/Functional_programming" target="_blank">"programming paradigm where programs
|
|
are
|
|
constructed by applying and composing functions"</a>. In laymen terms, a majority of the code written in these
|
|
languages is just functions. Everything can be expressed as some composition of functions. For this reason, a
|
|
strong understanding of mathematics can be hugely beneficial to functional programmers.</p>
|
|
<blockquote>"Functional programming evolved from lambda calculus" </blockquote>
|
|
<h4>Pure Functions</h4>
|
|
<p>Another key difference between other paradigms is the strict immutability. Functional programming introduces the
|
|
term "<a href="https://en.wikipedia.org/wiki/Pure_function" target="_blank">pure function</a>" which is any
|
|
function that can be run (any amount of times) and will always produce the same output, <strong>and cannot be
|
|
affected by (or affect) any mutable state.</strong> The intention of writing pure functions is to prevent <a
|
|
href="https://en.wikipedia.org/wiki/Side_effect_(computer_science" target="_blank">side effects</a>), "any
|
|
observable effect other than its primary purpose."</p>
|
|
<p>To simplify, the two properties of a <strong>pure</strong> function are:</p>
|
|
<p>1) The function will return an identical result for identical arguments. With <strong><em>no</em></strong>
|
|
variation for any reason, including reference arguments. 2) The function has no <em>side effects</em>, no mutation
|
|
of local static variables, non-local variables, etc.)</p>
|
|
<p>An example of a pure function in C++ may look as follows:</p>
|
|
<code>
|
|
c++
|
|
<br>
|
|
void f() {
|
|
<br>
|
|
static std::atomic<unsigned int> x = 0;
|
|
<br>
|
|
++x;
|
|
<br>
|
|
}
|
|
<br>
|
|
|
|
</code>
|
|
<p>The function <code>f()</code> is pure because it follows the above properties.</p>
|
|
<code>
|
|
c++
|
|
<br>
|
|
int f_i() {
|
|
<br>
|
|
static int x = 0;
|
|
<br>
|
|
++x;
|
|
<br>
|
|
return x;
|
|
<br>
|
|
}
|
|
<br>
|
|
|
|
</code>
|
|
<p>However, the function <code>f_i()</code> is impure because it returns a variation of a static variable.</p>
|
|
<p>Countless more examples of impure functions can be found <a
|
|
href="https://en.wikipedia.org/wiki/Pure_function#Impure_functions" target="_blank">here</a>.</p>
|
|
<p><strong>NOTE:</strong> I wanted to write these examples in Elixir, but due to its functional nature, it would be
|
|
very hard.</p>
|
|
<p><br></p>
|
|
<h4>Functions are First Class Citizens</h4>
|
|
<p>Another key property of functional programming is that functions are known as <a
|
|
href="https://en.wikipedia.org/wiki/First-class_citizen" target="_blank">first class citizens</a> which means
|
|
they can be assigned to variables, passed into other functions as arguments (<a
|
|
href="https://en.wikipedia.org/wiki/Higher-order_function" target="_blank">higher order functions</a>) and
|
|
returned from functions. This is not uncommon in modern programming languages so I will not provide an in-depth
|
|
explanation.</p>
|
|
<p><br></p>
|
|
<h4>Recursion</h4>
|
|
<p>The death of many modern programming languages, recursion, is one of the many strengths of functional languages.
|
|
<a href="https://en.wikipedia.org/wiki/Recursion_(computer_science" target="_blank">Recursion</a>) occurs when a
|
|
functions calls itself. This is the most common way to implement <a href="https://en.wikipedia.org/wiki/Iteration"
|
|
target="_blank">iteration</a> in functional programming. For example a simple loop in any common procedural
|
|
language:
|
|
</p>
|
|
<code>
|
|
c++
|
|
<br>
|
|
std::vector<int> numbers = {1, 2, 4, 8, 16};
|
|
<br>
|
|
|
|
<br>
|
|
for (size_t i = 0; i < numbers.size(); i++) { <br>
|
|
std::cout << numbers[i] << " " ; <br>
|
|
}
|
|
<br>
|
|
|
|
</code>
|
|
<p>Can be written in a similar way using recursion with Elixir:</p>
|
|
<code>
|
|
Elixir
|
|
<br>
|
|
def print_list([]), do: IO.puts("") # Base case: when the list is empty, this function is called
|
|
<br>
|
|
|
|
<br>
|
|
def print_list([head | tail]) do
|
|
<br>
|
|
IO.puts(head) # Print the first element in the list (head)
|
|
<br>
|
|
print_list(tail) # Call the function again with the remaining elements
|
|
<br>
|
|
end
|
|
<br>
|
|
|
|
</code>
|
|
<p>Programmers coming from other languages might freak when they see so much recursion, and it is not wrong to
|
|
worry. In procedural languages, recursion requires the stack to keep a record of each function call, and when
|
|
recursion is used to extreme levels, the stack becomes very large and uses lots of memory. Not very efficient!
|
|
However, functional programming languages found a solution, <a href="https://en.wikipedia.org/wiki/Tail_call"
|
|
target="_blank">tail recursion</a>. Tail recursion allows the compiler to creation a subroutine which represents
|
|
the final action (final function call) and place it onto the stack, allowing the program to jump right to the end
|
|
without having to store the entire recursive loop in stack memory. This reduces the memory stack space from linear
|
|
or O(N) to constant or O(1). A huge performance increases in recursive programs.</p>
|
|
<p><br></p>
|
|
<h4>Strict vs. Non-Strict Evaluation</h4>
|
|
<p>Functional languages can be categorized by <em>strict (eager)</em> or <em>non-strict (lazy)</em> evaluation. The
|
|
"Functional programming evolved from lambda calculus"
|
|
different evaluation styles refer to how arguments are processed inside an expression under evaluation. This
|
|
concept is quite complex and this overview does not warrant the necessity for such details. However, a simple
|
|
example can explain (on a higher level) the difference. <strong>"Under strict evaluation, the evaluation of any
|
|
term containing
|
|
a failing subterm fails.</strong> An example makes this a bit easier to understand. We will use the same example
|
|
to described both evaluation types.</p>
|
|
<code>
|
|
|
|
<br>
|
|
print length([2+1, 3*2, 1/0, 5-4])
|
|
<br>
|
|
|
|
</code>
|
|
<p>In a language categorized as <em>strict</em>, the expression above will fail, due to the term <code>1/0</code>
|
|
failing. However, in a language with <em>non-strict</em> evaluation, the length expression will return 4 because
|
|
it does attempt to evaluate the subterms, which result in failure.</p>
|
|
<p>To summarize, <em>lazy</em> evaluation does not attempt to evaluate function arguments unless their values are
|
|
required for the function call itself.</p>
|
|
<p><strong><em>NOTE: Elixir is a strictly evaluated language.</em></strong></p>
|
|
<p><br></p>
|
|
<h4>Referential Transparency</h4>
|
|
<p>Another very detailed differentiation from imperative programming languages. <a
|
|
href="https://en.wikipedia.org/wiki/Referential_transparency" target="_blank">Referential transparency</a> stems
|
|
from linguistic roots and language by extension. Applications in this context (computer science) states that "a
|
|
language is <em>referentially
|
|
transparent</em> when an expression built from another, replaces the expression with a subexpression which
|
|
represents the same value and does not change the value of the expression." That sounds very complicated, and it
|
|
is, but to be simple, expressions cannot be modified, only replaced. </p>
|
|
<p>Functional programming languages do not have <strong>assignment statements</strong>, because a value can never be
|
|
changed once it is defined. This is a result of the language allowing variables to be swapped with their value at
|
|
any time. Therefore, functional languages are referentially transparent.</p>
|
|
<p>Another example will make this easier to understand. Consider the following assignment statement from <a
|
|
href="https://en.wikipedia.org/wiki/C_(programming_language" target="_blank">C</a>). This assignment changes the
|
|
value assigned to the variable <code>x</code>. If the initial value of <code>x</code> was to be <code>1</code>,
|
|
the result would be <code>10</code>. But when called again, the result would be <code>100</code>. Since replacing
|
|
<code>x</code> with <code>10</code> or <code>100</code> gives the program different meaning, it is not
|
|
<em>referentially transparent.</em>
|
|
</p>
|
|
<code>
|
|
c
|
|
<br>
|
|
x = x * 10
|
|
<br>
|
|
|
|
</code>
|
|
<p>However, consider the following elixir function, <code>f(x)</code>. This implementation is <em>transparent</em>,
|
|
as it does not modify the value of x, which results in the absence of <strong>side effects</strong>. Instead, it
|
|
returns a value which can be used to replace an existing value. This is the standard in functional languages which
|
|
results in their referential nature.</p>
|
|
<code>
|
|
elixir
|
|
<br>
|
|
def f(x) do
|
|
<br>
|
|
x + 1
|
|
<br>
|
|
end
|
|
<br>
|
|
|
|
</code>
|
|
<p><br></p>
|
|
<h4>Data Structures</h4>
|
|
<p>The last key difference between imperative and function languages is their representation of data structures.
|
|
Functional languages admit a <a href="https://en.wikipedia.org/wiki/Purely_functional_data_structure"
|
|
target="_blank">purely functional</a> data structure, where the biggest difference is immutability. Purely
|
|
functional data structures are strongly immutable, which allows for many advantages, such as <a
|
|
href="https://en.wikipedia.org/wiki/Persistent_data_structure" target="_blank">persistence</a>, quick copy and
|
|
<a href="https://en.wikipedia.org/wiki/Thread_safety" target="_blank">thread safety</a>. Of the advantages listed,
|
|
I will only go in detail about one: <strong>persistence.</strong> Purely functional data structures are persistent
|
|
which means that when modifications occur, the previous state will be kept unmodified. A common comparison is to
|
|
the non-persistent array which admits a <strong>destructive update</strong> which cannot be undone, since no
|
|
previous versions are kept.
|
|
</p>
|
|
<p><strong><em>NOTE: Elixir is not a purely functional language and as a result, does not implement a purely
|
|
functional data structure.</em></strong></p>
|
|
<h2>Why Functional?</h2>
|
|
<p>That was quite a long explanation, but it covered almost everything you would need to know to <em>begin</em>
|
|
learning a functional language. However, I did not explain why <strong>I</strong> decided to learn. Functional
|
|
languages are rarely faster (or even as fast) as imperative languages like C, so the choice was not made for
|
|
performance. The most obvious choice: <strong><em>I want to.</em></strong> So many software developers spend too
|
|
much time worrying about what is "the best" or "the fastest." Maybe they should just be learning what they
|
|
<strong>want.</strong>
|
|
</p>
|
|
<p>Like I stated in the background, I, like many others, run at the sight of functional languages, but its about
|
|
time I break that fear! The next sections of this article will highlight my experience learning the <strong>Elixir
|
|
Programming Language,</strong> so if you were only here for the functional definition, this is a good stopping
|
|
point.</p>
|
|
<h2>Why Elixir?</h2>
|
|
<p>I have talked a lot about Elixir language but what exactly is it? Obviously its a functional programming
|
|
language, but that's very vague. "<a href="https://elixir-lang.org" target="_blank">Elixir</a> is a dynamic,
|
|
functional language for building scalable and maintainable applications." Elixir runs on the <a
|
|
href="https://www.erlang.org" target="_blank">Erlang</a> VM which is known for creating fault tolerant,
|
|
low-latency, distributed systems. The language can be installed and testing in the interactive elixir shell
|
|
<code>iex</code>, similar to pythons interactive shell. The interactive shell was a great tool for my own learning
|
|
while reading through the documentation.
|
|
</p>
|
|
<p>Elixir was first released in <strong>2012</strong> which makes it a newer language, but not as new as some (Odin,
|
|
or Zig). With this comes a large user base as well as a large developer ecosystem. But, what makes elixir stand
|
|
out in that aspect is its compatibility with Erlang. Erlang, which appeared in <strong>1986</strong> has a huge
|
|
ecosystem of libraries and tools which work seamlessly in Elixir. Elixir comes packaged with a build tool,
|
|
<code>mix</code> which allows for compilation and interpretation of elixir code. Elixir <em>also</em> has a
|
|
dedicated package manager, <code>hex</code>, which is comparable to <code>npm</code> in terms of use. However,
|
|
Elixir's ecosystem does not compare to the JavaScript ecosystem (what language does?).
|
|
</p>
|
|
<p>One of the most popular uses of Elixir is with the <a href="https://www.phoenixframework.org"
|
|
target="_blank">Phoenix Web Framework</a>. Phoenix, a full stack web framework that boasts its countless
|
|
features which include <strong>LiveView</strong>, a tool for building real-time web applications. Another popular
|
|
library, <strong>[Ecto](https://hexdocs.pm/ecto/Ecto.html)</strong> is a SQL ORM that is built into the Phoenix
|
|
framework and allows for seamless database connections from your web application back end. (The Phoenix framework
|
|
will come up more later.)</p>
|
|
<p>But who cares? Well, many large companies you have heard of use Elixir in their software. Some of which include
|
|
WhatsApp, Discord, Heroku, Pepsico and <a href="https://elixir-lang.org/cases.html" target="_blank">more</a>.</p>
|
|
<h2>The Beginning</h2>
|
|
<p>Personally, I am of the believe the best (and maybe even only) way to learn a programming language is to build
|
|
something. No matter how many videos you watch, tutorials you read, or examples you look at, you will never fully
|
|
understand the nuances of a language until you have tried it out yourself. Of course, this does assume you have a
|
|
basic understanding of programming and software design. So, to adhere to my own advice, the first thing I did was
|
|
create a small project. The ever-dreaded, <strong>To-do List.</strong> </p>
|
|
<p>I choose this project because it is simple, I have written a million of them, it allows me to learn terminal I/O,
|
|
file I/O, basic data handling, and some more complex data types such as maps and lists. Typically, my first go-to
|
|
application when learning a new language is a simple web server. But, since I wanted to experiment with
|
|
<strong>Phoenix</strong> I decided to wait until after getting my hands on the language before trying such a
|
|
detailed framework.
|
|
</p>
|
|
<p>The application can be found on my GitHub <a href="https://github.com/haydenhargreaves/ElixirTodo"
|
|
target="_blank">here</a>. I would like to note, I did not spend much effort on the repo or making the UI very
|
|
beautiful. I hope you can understand that quality was not the goal here. </p>
|
|
<p>After writing this simple CLI tool I felt far more confident in my Elixir ability and the ability to read the
|
|
docs and find what I was looking for without just prompting an LLM to solve my problems.</p>
|
|
<p>But that reminds me, I actually lied to you. The first thing I did was <em>not</em> write the to-do list. No, the
|
|
very first thing I did was read through a good chunk of the <a href="https://hexdocs.pm/elixir/introduction.html"
|
|
target="_blank">Elixir Getting Started Guide</a>. In the past few years, I have tried my hand at over a dozen
|
|
programming languages, many of which I gave up on very fast. The most common complaint I have with modern
|
|
programming languages is their lack of comprehensive documentation. However, the Elixir documentation <em>blew my
|
|
socks off!</em> The documentation is <strong>amazing.</strong> Not only is it very easy to read, it
|
|
<strong>makes sense.</strong> I can remember trying to learn a few languages and trying to read their docs was a
|
|
nightmare, <em>cough cough, Zig.</em> After just a few hours, I had a pretty solid understanding of the language
|
|
at a semantic level and was able to read through more complicated examples with ease.
|
|
</p>
|
|
<p>The introduction linked above is a complete walk through of <em>almost</em> everything you would need to write
|
|
industry grade software in the Elixir language. Even after only reading through the first 10 or so sections, I was
|
|
beyond ready to begin writing code.</p>
|
|
<p>The <a href="https://hexdocs.pm/elixir/Kernel.html" target="_blank">modules</a> segment of the docs is just as
|
|
powerful, especially once you have jumped into the deep end of writing your own code. Documentation complete with
|
|
syntax, functions, types, a summary and even examples can be found for each and every module in the standard
|
|
library. It really is the best resource I have found (so far) for learning the language. Which is not something I
|
|
can say for other languages.</p>
|
|
<h2>An Upgrade</h2>
|
|
<p>So now I have written something small, and read through the documentation. What's next? Well, a large scale
|
|
application, duh! For this project, I will build a full stack web application using the Phoenix Framework. This
|
|
app will allow users to share, copy, create and search for recipes. I have recently developed a love for cooking
|
|
and having to store all my recipes in my notes app is cumbersome. Plus, my parents are <strong>amazing</strong>
|
|
cooks and I would to be able to "borrow" their recipes and save them for myself, without having to copy them
|
|
manually.</p>
|
|
<h2>Elixir Review</h2>
|
|
<p>The learning process has been put on pause to focus on work, but when I make it back to Elixir, I will finish the
|
|
conclusion!</p>
|
|
</div>
|
|
|
|
</body>
|
|
|
|
</html>
|