DEV Community

loading...

Learning Elixir part 1

wkulikowski profile image Wojtek Kulikowski ・4 min read

Alt Text

This post has been originally published at my personal website

Learning a new language

Everybody needs to reset from time to time. For some this includes
travel. Some need to binge 2 seasons of their favorite Netflix show.
For some a free evening in their coffee shop of choice will do.

And nerds pick up some new fancy tech found on HackerNews.

Welcome to my world, my name is Wojtek and today we will try to pick
inside the world of functional programming and it's most promising
child – Elixir.

Personal context

This series will describe my personal experience with the tool.
Why Elixir? Let's jump into facts:

  • I write Python applications for a living
  • I have never taken a functional programming class in college
  • Sometimes it is refreshing to get punched in the face

So this would be my reset. Although we have lambda functions in
ython (and I love them!), map/reduce is the only functional concept
I know. Heard some jokes about monads.

Why Elixir?

I have first heard about Elixir while binge watching YouTube and
stumbling upon this video

From a perspective of Django developer it left me with a mind blown away.

First, asynchronous python is tricky and probably needs some more
time to be widely accessible. Although some great work is happening right
now (Andrew, if you're reading
this by any chance, I am a fan!), achieving 2 million websocket connections on single machine would be a stretch for Python. Andrew explained the bottlenecks in this thread.

Second, LiveView gives me an opportunity to write frontend in the same
codebase as backend. It doesn't necessarily have to be a good thing, but
certainly helps with the framework fatigue, while preserving the
interactivity of a SPA.

Getting hands dirty

Let's get down to the actual hacking. Here are some goals I have in mind
for this experiment:

  1. Solve some HackerRank challenges with Elixir. Same basic syntax and IO understanding will not hurt
  2. Learn more about functional programming. So this is where the Y combinator got its name from!
  3. Implement some basic http server with Phoenix and expose it with Cowboy
  4. Write a simple real-time project with LiveView.

Hackerrank

Let's start with 2 warmup challenges on HackerRank. Please don't ever try
to reuse this code! This is before following any tutorials, first try at
implementing something with docs and my (imperative) intuition.

Simple array sum (product)

This tasks resolves around reading an array and then multiplying all of
its numbers together. How to approach it?

IO.gets("Input numbers to multiply: ")
|> String.split
|> Enum.map(&String.to_integer/1)
|> Enum.reduce(fn x, acc -> x * acc end)
Enter fullscreen mode Exit fullscreen mode

First, we need to read the input. By default, IO.gets/2 reads all input
to a string. To make it into a list we need to use the String.split/1 function. So far so good! It doesn't seem so different from Python.

But hey, what are these weird arrows? They are called pipes! It is an elegant way of passing output of one function to the other. In python you
would have to produce a really long line, while elixir allows for this
elegant, vertical structure. So far one of my favorite features.

Coming back to the task, here we start map/reduce part. First, we need to
cast every string in the list to an integer. This is achieved by mapping
function String.to_integer/1.

Once we have a list of integers, we want to reduce it. Here happens the
main part of the algorithm. We iterate through every element in the array
and store their product in the accumulator acc. That is it!

Compare the triplets (n-lets)

Second challenge resolves around Alice and Bob playing a game and comparing their scores in every round. So if Alice's scores were: 1, 2, 5,3, 9 and Bob's 2, 2, 5, 1, 5, the score of the game is 2:1 for Alice.

I feel like I did much worse on this one – my Python implementation would
not require an additional array and only 1 iteration would do. The if
statement seems also really out of touch and this code simply smells.
Can't wait to refactor it later in the journey!

alice_points = IO.gets("Input Alice points: ")
|> String.split

bob_points = IO.gets("Input Bob points: ")
|> String.split

scores = Enum.map(0..(length(alice_points)-1), fn x ->
  if Enum.at(alice_points, x) > Enum.at(bob_points, x) do
    1
  else if Enum.at(alice_points, x) < Enum.at(bob_points, x) do
    -1
  else
    0
  end
end
end
)

alice_score = Enum.reduce(scores, 0, fn x, acc -> if x == 1, do: acc+1, else: acc end)

bob_score = Enum.reduce(scores, 0, fn x, acc -> if x == -1, do: acc+1, else: acc end)

IO.puts "Alice: #{alice_score}, Bob: #{bob_score}"
Enter fullscreen mode Exit fullscreen mode

The algorithm above uses map/reduce to track the outcome of each
round and then reduce it to calculate the scores for each player. It is
really simple, but takes enormous amount of space and surely, it is not
optimal.

Next steps

So far so good! Although I discovered that writing up is actually harder
than tinkering with Elixir, I will continue to do both.

Goals for the next week:

Gonna be exciting, let's move forwards 🚀

Discussion (2)

pic
Editor guide
Collapse
wkulikowski profile image
Wojtek Kulikowski Author

Hi all! This is my first time publishing here. I will appriciate literally ANY feedback 😅 Love!

Collapse
colewalker profile image
Cole Walker

Great article, really enjoy your writing style. Learned a lot!