diff --git a/src/journal/What is a Functional Programming Language: Featuring Elixir.md b/src/journal/What is a Functional Programming Language: Featuring Elixir.md new file mode 100644 index 0000000..de9c239 --- /dev/null +++ b/src/journal/What is a Functional Programming Language: Featuring Elixir.md @@ -0,0 +1,257 @@ +Date: 2025/04/28 +Desc: I have decided to begin the journey of learning functional programming. Here is my experience. + +# What is a Functional Programming Language: Featuring Elixir.md + +Jet Brains Logo + +
+ +###### Author: Hayden Hargreaves + +###### Published: 05/??/2025 + +## Background + +Many programmers tend to avoid **functional programming** 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, [monads](https://en.wikipedia.org/wiki/Monad_(functional_programming)), [functors](https://en.wikipedia.org/wiki/Functor), and all those *scary* terms frequently tossed around in the functional +space. + +How am I going to do this? Well, I am definitely not going to start with [Haskell](https://www.haskell.org). 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. + +```haskell +primes = filterPrime [2..] where + filterPrime (p:xs) = + p : filterPrime [x | x <- xs, x `mod` p /= 0] +``` + +Personally, the Haskell language is far too esoteric for my liking. Eventually, I would love to be able +to, at the very least, **read** 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 **Python** or **JavaScript** which can be +written to *seem* functional. No, I wanted to write a **real** functional language. A common list of as +follows: + +- [Haskell](https://www.haskell.org) +- [Erlang](https://www.erlang.org) +- **[Elixir](https://elixir-lang.org)** +- [Scala](https://www.scala-lang.org) +- [Clojure](https://clojure.org) +- [OCaml](https://ocaml.org) +- [Common Lisp](https://lisp-lang.org) + +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 **OCaml** 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 [Elixir](https://www.reddit.com/r/elixir/) Reddit page was very informative as well as providing me with a link to the +[2024 Stack Overflow Survey](https://survey.stackoverflow.co/2024/technology#top-paying-technologies) which described Erlang and Elixir as the top two paying languages. + +With that out of the way, lets talk more about what functional programming is. + +## What is Functional Programming + +At the most basic level, functional programming is defined as a ["programming paradigm where programs are +constructed by applying and composing functions"](https://en.wikipedia.org/wiki/Functional_programming). 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. + +> +> "Functional programming evolved from lambda calculus" +> + +#### Pure Functions + +Another key difference between other paradigms is the strict immutability. Functional programming introduces +the term "[pure function](https://en.wikipedia.org/wiki/Pure_function)" which is any function that can be run (any amount of times) and will always produce +the same output, **and cannot be affected by (or affect) any mutable state.** The intention of writing pure +functions is to prevent [side effects](https://en.wikipedia.org/wiki/Side_effect_(computer_science)), "any observable effect other than its primary purpose." + +To simplify, the two properties of a **pure** function are: + +1) The function will return an identical result for identical arguments. With ***no*** variation for any reason, +including reference arguments. +2) The function has no *side effects*, no mutation of local static variables, non-local variables, etc.) + +An example of a pure function in C++ may look as follows: + +```c++ +void f() { + static std::atomic x = 0; + ++x; +} +``` + +The function `f()` is pure because it follows the above properties. + +```c++ +int f_i() { + static int x = 0; + ++x; + return x; +} +``` + +However, the function `f_i()` is impure because it returns a variation of a static variable. + +Countless more examples of impure functions can be found [here](https://en.wikipedia.org/wiki/Pure_function#Impure_functions). + +**NOTE:** I wanted to write these examples in Elixir, but due to its functional nature, it would be very hard. + +
+ +#### Functions are First Class Citizens + +Another key property of functional programming is that functions are known as [first class citizens](https://en.wikipedia.org/wiki/First-class_citizen) which +means they can be assigned to variables, passed into other functions as arguments ([higher order functions](https://en.wikipedia.org/wiki/Higher-order_function)) +and returned from functions. This is not uncommon in modern programming languages so I will not provide an +in-depth explanation. + +
+ +#### Recursion + +The death of many modern programming languages, recursion, is one of the many strengths of functional languages. +[Recursion](https://en.wikipedia.org/wiki/Recursion_(computer_science)) occurs when a functions calls itself. This is the most common way to implement [iteration](https://en.wikipedia.org/wiki/Iteration) in +functional programming. For example a simple loop in any common procedural language: + +```c++ +std::vector numbers = {1, 2, 4, 8, 16}; + +for (size_t i = 0; i < numbers.size(); i++) { + std::cout << numbers[i] << " "; +} +``` + +Can be written in a similar way using recursion with Elixir: + +```Elixir +def print_list([]), do: IO.puts("") # Base case: when the list is empty, this function is called + +def print_list([head | tail]) do + IO.puts(head) # Print the first element in the list (head) + print_list(tail) # Call the function again with the remaining elements +end +``` + +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, [tail recursion](https://en.wikipedia.org/wiki/Tail_call). 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. + +
+ +#### Strict vs. Non-Strict Evaluation + +Functional languages can be categorized by *strict (eager)* or *non-strict (lazy)* evaluation. The 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. **"Under strict evaluation, the evaluation of any term containing +a failing subterm fails.** An example makes this a bit easier to understand. We will use the same example to described +both evaluation types. + +``` +print length([2+1, 3*2, 1/0, 5-4]) +``` + +In a language categorized as *strict*, the expression above will fail, due to the term `1/0` failing. However, in a language +with *non-strict* evaluation, the length expression will return 4 because it does attempt to evaluate the subterms, which +result in failure. + +To summarize, *lazy* evaluation does not attempt to evaluate function arguments unless their values are required for the +function call itself. + +***NOTE: Elixir is a strictly evaluated language.*** + +
+ +#### Referential Transparency + +Another very detailed differentiation from imperative programming languages. [Referential transparency](https://en.wikipedia.org/wiki/Referential_transparency) stems from linguistic +roots and language by extension. Applications in this context (computer science) states that "a language is *referentially +transparent* 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. + +Functional programming languages do not have **assignment statements**, 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. + +Another example will make this easier to understand. Consider the following assignment statement from [C](https://en.wikipedia.org/wiki/C_(programming_language)). This assignment changes +the value assigned to the variable `x`. If the initial value of `x` was to be `1`, the result would be `10`. But when called again, the +result would be `100`. Since replacing `x` with `10` or `100` gives the program different meaning, it is not *referentially transparent.* + +```c +x = x * 10 +``` + +However, consider the following elixir function, `f(x)`. This implementation is *transparent*, as it does not modify the value of x, +which results in the absence of **side effects**. 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. + +```elixir +def f(x) do + x + 1 +end +``` + +
+ +#### Data Structures + +The last key difference between imperative and function languages is their representation of data structures. Functional languages +admit a [purely functional](https://en.wikipedia.org/wiki/Purely_functional_data_structure) data structure, where the biggest difference is immutability. Purely functional data structures are +strongly immutable, which allows for many advantages, such as [persistence](https://en.wikipedia.org/wiki/Persistent_data_structure), quick copy and [thread safety](https://en.wikipedia.org/wiki/Thread_safety). +Of the advantages listed, I will only go in detail about one: **persistence.** 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 **destructive update** which cannot be undone, since no previous versions are kept. + +***NOTE: Elixir is not a purely functional language and as a result, does not implement a purely functional data structure.*** + + +## Why Functional? + +That was quite a long explanation, but it covered almost everything you would need to know to *begin* learning a functional language. +However, I did not explain why **I** 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: ***I want to.*** 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 **want.** + +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 **Elixir Programming Language,** so if you were only here for +the functional definition, this is a good stopping point. + +## Why Elixir? + +I have talked a lot about Elixir language but what exactly is it? Obviously its a functional programming language, but that's very vague. +"[Elixir](https://elixir-lang.org) is a dynamic, functional language for building scalable and maintainable applications." Elixir runs on the [Erlang](https://www.erlang.org) VM which is +known for creating fault tolerant, low-latency, distributed systems. The language can be installed and testing in the interactive elixir shell +`iex`, similar to pythons interactive shell. The interactive shell was a great tool for my own learning while reading through the documentation. + +Elixir was first released in **2012** 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 **1986** has a huge ecosystem of libraries and tools which work seamlessly in Elixir. Elixir comes packaged with a build tool, `mix` which allows +for compilation and interpretation of elixir code. Elixir *also* has a dedicated package manager, `hex`, which is comparable to `npm` in terms of +use. However, Elixir's ecosystem does not compare to the JavaScript ecosystem (what language does?). + +One of the most popular uses of Elixir is with the [Phoenix Web Framework](https://www.phoenixframework.org). Phoenix, a full stack web framework that boasts its countless features +which include **LiveView**, a tool for building real-time web applications. Another popular library, **[Ecto](https://hexdocs.pm/ecto/Ecto.html)** 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.) + + +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 [more](https://elixir-lang.org/cases.html). + +## The Beginning + + + +The repo: +https://github.com/haydenhargreaves/ElixirTodo + diff --git a/static/journal/elixir-logo.png b/static/journal/elixir-logo.png new file mode 100644 index 0000000..737034f Binary files /dev/null and b/static/journal/elixir-logo.png differ